Update documentation for reCAPTCHA support
Signed-off-by: Lucy Linder <lucy.derlin@gmail.com>
This commit is contained in:
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 |
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in a new issue