RedFroggy / keycloak-registration-invitation

Register user with invitation
MIT License
33 stars 8 forks source link

Compatible with latest KeyCloak? #1

Open bard opened 3 years ago

bard commented 3 years ago

Thanks for sharing this work! I've seen tickets going as far back as 2015 asking for something like it, with little effect, so I could hardly believe my eyes when I saw it pop up in Github's search results.

Reading the code, I see that invitation-code is intended to be passed as URL param. So I went to the login page, clicked on "Register", and appended invitation-code=abc123 to the URL, to see if it would work:

<keycloak>/auth/realms/<realm>/login-actions/registration?client_id=account&tab_id=3DM0IU03OiI&invitation-code=abc123

Is that correct?

When I do that, I get this in KeyCloak's logs:

ERROR [org.keycloak.services.error.KeycloakErrorHandler] (default task-351) Uncaught server error: java.lang.NoSuchMethodError: 'org.apache.http.client.HttpClient org.keycloak.connections.httpclient.HttpClientProvider.getHttpClient()'
    at deployment.keycloak-registration-invitation-11.0-SNAPSHOT.jar//fr.redfroggy.keycloak.invitation.forms.RegistrationInvitation.validateInvitation(RegistrationInvitation.java:159)
    at deployment.keycloak-registration-invitation-11.0-SNAPSHOT.jar//fr.redfroggy.keycloak.invitation.forms.RegistrationInvitation.buildPage(RegistrationInvitation.java:90)
    at org.keycloak.keycloak-services@15.0.2//org.keycloak.authentication.FormAuthenticationFlow.renderForm(FormAuthenticationFlow.java:304)
    at org.keycloak.keycloak-services@15.0.2//org.keycloak.authentication.FormAuthenticationFlow.processFlow(FormAuthenticationFlow.java:285)
    at org.keycloak.keycloak-services@15.0.2//org.keycloak.authentication.DefaultAuthenticationFlow.processSingleFlowExecutionModel(DefaultAuthenticationFlow.java:389)
    at org.keycloak.keycloak-services@15.0.2//org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:253)
    at org.keycloak.keycloak-services@15.0.2//org.keycloak.authentication.AuthenticationProcessor.authenticateOnly(AuthenticationProcessor.java:990)
    at org.keycloak.keycloak-services@15.0.2//org.keycloak.authentication.AuthenticationProcessor.authenticate(AuthenticationProcessor.java:852)
    at org.keycloak.keycloak-services@15.0.2//org.keycloak.services.resources.LoginActionsService.processFlow(LoginActionsService.java:314)
    at org.keycloak.keycloak-services@15.0.2//org.keycloak.services.resources.LoginActionsService.processRegistration(LoginActionsService.java:656)
    at org.keycloak.keycloak-services@15.0.2//org.keycloak.services.resources.LoginActionsService.registerRequest(LoginActionsService.java:712)
    at org.keycloak.keycloak-services@15.0.2//org.keycloak.services.resources.LoginActionsService.registerPage(LoginActionsService.java:673)
    at jdk.internal.reflect.GeneratedMethodAccessor1201.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)
[...]

getHttpClient seems to be there: https://github.com/keycloak/keycloak/blob/c3a15cb368eaa20d6af362926e1d77e7d96f7420/services/src/main/java/org/keycloak/connections/httpclient/DefaultHttpClientFactory.java#L75

Any idea of what might be going wrong?

Pfuenzle commented 2 years ago

Did you have any success with this extension? Im not getting the same error as you do, but the "Invitation validation url" is not being accessed and the account is created regardless

bard commented 2 years ago

@Pfuenzle I didn't. But I was able to use built-in functionality to mostly replicate an invitation flow. Here it is in case you may find it useful:

  1. In the Manage > Users section of the GUI, Create a user with User Enabled: true, Email Verified: true, and Required User Actions: Update Password
  2. In the Credentials tab, set a temporary password. This will act as the "invitation code"
  3. Send them a mail containing the "invitation code" and a link to your app's OAuth URL, e.g.: https://myapp.com/oauth2/start?login_hint=bob@example.com
  4. User will click on the link, enter the "invitation code", set the final password, and will be logged in.

In step 3), the service or library that handles the OAuth endpoint needs to know that the login_hint query parameter must be forwarded to KeyCloak. At the time, I was using oauth2-proxy and had to sligthly modify to add that. The flow would work in principle even without it, but the user would have to enter the email on the first step, which significantly degrades the experience.

csbrogi commented 2 years ago

I tried to compile the plugin with the latest kc (16.1.0) and I got compilation errors one is: when(httpClientProvider.getHttpClient()).thenReturn(httpClient); in mockChallenge if I add a cast when(httpClientProvider.getHttpClient()).thenReturn((CloseableHttpClient) httpClient); I get a run-time -error:


[ERROR] fr.redfroggy.keycloak.invitation.requiredactions.WebhookRegistrationSuccessTest.shouldChallengeErrorWhenUnexceptedException  Time elapsed: 0.003 s  <<< ERRO
R!
java.lang.ClassCastException: class org.apache.http.client.HttpClient$MockitoMock$148537412 cannot be cast to class org.apache.http.impl.client.CloseableHttpClient 
(org.apache.http.client.HttpClient$MockitoMock$148537412 and org.apache.http.impl.client.CloseableHttpClient are in unnamed module of loader 'app')
        at fr.redfroggy.keycloak.invitation.requiredactions.WebhookRegistrationSuccessTest.mockChallenge(WebhookRegistrationSuccessTest.java:140)
        at fr.redfroggy.keycloak.invitation.requiredactions.WebhookRegistrationSuccessTest.shouldChallengeErrorWhenUnexceptedException(WebhookRegistrationSuccessTes
t.java:117)