Update documentation for reCAPTCHA support

Signed-off-by: Lucy Linder <lucy.derlin@gmail.com>
This commit is contained in:
Lucy Linder 2024-02-03 17:22:26 +01:00 committed by Pedro Igor
parent aa6771205a
commit 84d48a9877
4 changed files with 78 additions and 36 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

View file

@ -6,19 +6,20 @@
= Enabling reCAPTCHA
[role="_abstract"]
To safeguard registration against bots, {project_name} has integration with Google reCAPTCHA.
To safeguard registration against bots, {project_name} has integration with Google reCAPTCHA (see <<procedure_recaptcha>>) and reCAPTCHA Enterprise (see <<procedure_recaptcha_enterprise>>).
The default theme (`register.ftl`) supports both v2 (visible, checkbox-based) and v3 (score-based, invisible) reCAPTCHA (see https://cloud.google.com/recaptcha-enterprise/docs/choose-key-type[Choose the appropriate reCAPTCHA key type]).
Once reCAPTCHA is enabled, you can edit `register.ftl` in your login theme to configure the placement and styling of the reCAPTCHA button on the registration page.
[[procedure_recaptcha]]
== Setting up Google reCAPTCHA
.Procedure
. Enter the following URL in a browser:
+
[source,bash,subs=+attributes]
----
https://developers.google.com/recaptcha/
https://www.google.com/recaptcha/admin/create
----
. Create an API key to get your reCAPTCHA site key and secret. Note the reCAPTCHA site key and secret for future use in this procedure.
. Create a reCAPTCHA and choose between Challenge v2 (visible checkbox) or Score-based, v3 (invisible) to get your reCAPTCHA site key and secret. Note them down for future use in this procedure.
+
NOTE: The localhost works by default. You do not have to specify a domain.
+
@ -29,22 +30,64 @@ NOTE: The localhost works by default. You do not have to specify a domain.
. Set the *reCAPTCHA* requirement to *Required*. This enables
reCAPTCHA.
. Click the *gear icon* ⚙️ on the *reCAPTCHA* row.
. Click the *Config* link.
+
.Recaptcha config page
.reCAPTCHA config
image:images/recaptcha-config.png[]
.. Enter the *Recaptcha Site Key* generated from the Google reCAPTCHA website.
.. Enter the *Recaptcha Secret* generated from the Google reCAPTCHA website.
.. Enter the *reCAPTCHA Site Key* generated from the Google reCAPTCHA website.
.. Enter the *reCAPTCHA Secret* generated from the Google reCAPTCHA website.
.. Toggle **reCAPTCHA v3** according to your Site Key type: on for score-based reCAPTCHA (v3), off for challenge reCAPTCHA (v2).
.. (Optional) Toggle *Use recaptcha.net* to use `www.recatcha.net` instead of `www.google.com` domain for cookies. See https://developers.google.com/recaptcha/docs/faq[reCAPTCHA faq] for more information.
. Authorize Google to use the registration page as an iframe.
+
NOTE: In {project_name}, websites cannot include a login page dialog in an iframe. This restriction is to prevent clickjacking attacks. You need to change the default HTTP response headers that is set in {project_name}.
+
.. Click *Realm Settings* in the menu.
.. Click the *Security Defenses* tab.
.. Enter `https://www.google.com` in the field for the *X-Frame-Options* header.
.. Enter `https://www.google.com` in the field for the *Content-Security-Policy* header.
.. Enter `https://www.google.com` in the field for the *X-Frame-Options* header (or `https//www.recaptcha.net` if you enabled *Use recaptcha.net*).
.. Enter `https://www.google.com` in the field for the *Content-Security-Policy* header (or `https//www.recaptcha.net` if you enabled *Use recaptcha.net*).
[[procedure_recaptcha_enterprise]]
== Setting up Google reCAPTCHA Enterprise
. Enter the following URL in a browser:
+
[source,bash,subs=+attributes]
----
https://developers.google.com/recaptcha/
----
. Create a key for a "Website" platform, and choose the desired key type. Leave the defaults for v3 reCAPTCHA (invisible), or toggle *Use checkbox challenge* for a v2 reCAPTCHA (visible). Note the site key for future use in this procedure.
+
NOTE: The localhost works by default. You do not have to specify a domain.
+
. On your Google Cloud Project, go to *Credentials* and create an API key.
+
NOTE: For better security, click on *edit api key* and add an API restriction to restrict the key to the *reCAPTCHA Enterprise API* only.
+
. Navigate to the {project_name} Admin Console.
. Click *Authentication* in the menu.
. Click the *Flows* tab.
. Duplicate the "registration" flow.
. Bind the new flow to the *Registration flow*.
. Edit the new flow:
.. Delete the *reCAPTCHA* step.
.. Add the step *reCAPTCHA Enterprise* as a sub-step of "registration form" (first step of the flow).
. Set the *reCAPTCHA Enterprise* requirement to *Required*.
. Click the *gear icon* ⚙️ on the *reCAPTCHA Enterprise* row.
+
.reCAPTCHA Enterprise config
image:images/recaptcha-enterprise-config.png[]
.. Enter the *Recaptcha Project ID* of your Google Cloud console project.
.. Enter the *Recaptcha Site Key* generated at the beginning of the procedure.
.. Enter the *Recaptcha API Key* generated at the beginning of the procedure.
.. Toggle **reCAPTCHA v3** according to your Site Key type: on for score-based reCAPTCHA (v3), off for challenge reCAPTCHA (v2).
.. (Optional) Customize the *Min. Score Threshold* as you see fit. Set it to the minimum score, between 0.0 and 1.0, that a user should achieve on reCAPTCHA to be allowed to register. See https://cloud.google.com/recaptcha-enterprise/docs/interpret-assessment-website#interpret_scores[interpret scores].
.. (Optional) Toggle *Use recaptcha.net* to use `www.recatcha.net` instead of `www.google.com` domain for cookies. See https://developers.google.com/recaptcha/docs/faq[reCAPTCHA faq] for more information.
. Authorize Google to use the registration page as an iframe. See the last steps of <<procedure_recaptcha>> for a detailed procedure.
[role="_additional-resources"]
.Additional resources

View file

@ -1,6 +1,7 @@
[[_auth_spi]]
== Authentication SPI
{project_name} includes a range of different authentication mechanisms: kerberos, password, otp and others.
These mechanisms may not meet all of your requirements and you may want to plug in your own custom ones.
{project_name} provides an authentication SPI that you can use to write new plugins.
@ -8,7 +9,7 @@ The Admin Console supports applying, ordering, and configuring these new mechani
{project_name} also supports a simple registration form.
Different aspects of this form can be enabled and disabled for example
Recaptcha support can be turned off and on.
reCAPTCHA support can be turned off and on.
The same authentication SPI can be used to add another page to the registration flow or reimplement it entirely.
There's also an additional fine-grained SPI you can use to add specific validations and user extensions to the built-in registration form.
@ -940,7 +941,7 @@ It is entirely possible for you to implement your own flow with a set of Authent
But what you'll usually want to do is just add a bit of validation to the out-of-the-box registration page.
An additional SPI was created to be able to do this.
It basically allows you to add validation of form elements on the page as well as to initialize UserModel attributes and data after the user has been registered.
We'll look at both the implementation of the user profile registration processing as well as the registration Google Recaptcha plugin.
We'll look at both the implementation of the user profile registration processing as well as the registration Google reCAPTCHA Enterprise plugin.
==== Implementation FormAction interface
@ -953,18 +954,24 @@ Rendering is done in the buildPage() method, validation is done in the validate(
@Override
public void buildPage(FormContext context, LoginFormsProvider form) {
AuthenticatorConfigModel captchaConfig = context.getAuthenticatorConfig();
if (captchaConfig == null || captchaConfig.getConfig() == null
|| captchaConfig.getConfig().get(SITE_KEY) == null
|| captchaConfig.getConfig().get(SITE_SECRET) == null
) {
Map<String, String> config = context.getAuthenticatorConfig().getConfig();
if (config == null
|| Stream.of(PROJECT_ID, SITE_KEY, API_KEY, ACTION)
.anyMatch(key -> Strings.isNullOrEmpty(config.get(key)))
|| parseDoubleFromConfig(config, SCORE_THRESHOLD) == null) {
form.addError(new FormMessage(null, Messages.RECAPTCHA_NOT_CONFIGURED));
return;
}
String siteKey = captchaConfig.getConfig().get(SITE_KEY);
String userLanguageTag = context.getSession().getContext().resolveLocale(context.getUser())
.toLanguageTag();
boolean invisible = Boolean.parseBoolean(config.getOrDefault(INVISIBLE, "true"));
form.setAttribute("recaptchaRequired", true);
form.setAttribute("recaptchaSiteKey", siteKey);
form.addScript("https://www.google.com/recaptcha/api.js");
form.setAttribute("recaptchaSiteKey", config.get(SITE_KEY));
form.setAttribute("recaptchaAction", config.get(ACTION));
form.setAttribute("recaptchaVisible", !invisible);
form.addScript("https://www.google.com/recaptcha/enterprise.js?hl=" + userLanguageTag);
}
----
@ -975,11 +982,11 @@ You can add additional attributes to the form provider so that they can be displ
The code above is from the registration recaptcha plugin.
Recaptcha requires some specific settings that must be obtained from configuration.
FormActions are configured in the exact same as Authenticators are.
In this example, we pull the Google Recaptcha site key from configuration and add it as an attribute to the form provider.
Our registration template file can read this attribute now.
In this example, we pull the Google Recaptcha site key and other options from Recaptcha configuration and add them as attributes to the form provider.
Our registration template file, register.ftl, can now have access to those attributes.
Recaptcha also has the requirement of loading a JavaScript script.
You can do this by calling LoginFormsProvider.addScript() passing in the URL.
You can do this by calling LoginFormsProvider.addScript(), passing in the URL.
For user profile processing, there is no additional information that it needs to add to the form, so its buildPage() method is empty.
@ -993,33 +1000,25 @@ Let's look at the Recaptcha's plugin first.
@Override
public void validate(ValidationContext context) {
MultivaluedMap<String, String> formData = context.getHttpRequest().getDecodedFormParameters();
List<FormMessage> errors = new ArrayList<>();
boolean success = false;
String captcha = formData.getFirst(G_RECAPTCHA_RESPONSE);
if (!Validation.isBlank(captcha)) {
AuthenticatorConfigModel captchaConfig = context.getAuthenticatorConfig();
String secret = captchaConfig.getConfig().get(SITE_SECRET);
success = validateRecaptcha(context, success, captcha, secret);
}
if (success) {
if (!Validation.isBlank(captcha) && validateRecaptcha(context, captcha)) {
context.success();
} else {
List<FormMessage> errors = new ArrayList<>();
errors.add(new FormMessage(null, Messages.RECAPTCHA_FAILED));
formData.remove(G_RECAPTCHA_RESPONSE);
context.validationError(formData, errors);
return;
}
}
----
Here we obtain the form data that the Recaptcha widget adds to the form.
We obtain the Recaptcha secret key from configuration.
We then validate the recaptcha.
If successful, ValidationContext.success() is called.
We clear the captcha token from the form using formData.remove, but keep other form data untouched.
If not, we invoke ValidationContext.validationError() passing in the formData (so the user doesn't have to re-enter data), we also specify an error message we want displayed.
The error message must point to a message bundle property in the internationalized message bundles.
For other registration extensions validate() might be validating the format of a form element, for example an alternative email attribute.