Skip to content

Commit

Permalink
feat: add internationalization in selector page (#10405)
Browse files Browse the repository at this point in the history
* docs: adjust docs as per new feature #10392

Signed-off-by: jgomer2001 <[email protected]>

* feat: allow internationalization in the selector page #10392

Signed-off-by: jgomer2001 <[email protected]>

* chore: update casa projects to support internationalization #10159

Signed-off-by: jgomer2001 <[email protected]>

* docs: minor rephrase #10392

Signed-off-by: jgomer2001 <[email protected]>

---------

Signed-off-by: jgomer2001 <[email protected]>
Co-authored-by: Mohammad Abudayyeh <[email protected]>
  • Loading branch information
jgomer2001 and moabu authored Dec 13, 2024
1 parent e5518cf commit 0198c32
Show file tree
Hide file tree
Showing 21 changed files with 162 additions and 70 deletions.
2 changes: 1 addition & 1 deletion agama/transpiler/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
<dependency>
<groupId>net.sf.saxon</groupId>
<artifactId>Saxon-HE</artifactId>
<version>10.5</version>
<version>12.5</version>
</dependency>
<dependency>
<groupId>com.yuvalshavit</groupId>
Expand Down
15 changes: 14 additions & 1 deletion docs/casa/developer/add-authn-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,20 @@ For example, if your authentication method is backed by a flow `com.acme.authn.f
}
```

Both `icon` and `text` may contain HTML markup. In this example we are using the font awesome library available in the selector page for rendering a nice [icon](https://fontawesome.com/v5/search?q=pizza&o=r&m=free) but we could have used any other thing here like an `img` tag, for instance.
Alternatively, a pointer to a localized message can be used instead of `text`. This is the recommended practice if [localization/internationalization](../../janssen-server/developer/agama/advanced-usages.md#localization-and-internationalization) is relevant. In this case, something like the below will work:

```
...
"com.acme.authn.food": {
"icon": "<i class='fas fa-pizza-slice'></i>",
"textKey": "foodAuth.methodTitle"
}
...
```

as long as the message key `foodAuth.methodTitle` is defined in the project's `labels.txt` file, or elsewhere in another project. Note `textKey` takes precedence over `text` when rendering the page.

Both `icon` and `textKey` (or `text`) may contain HTML markup. In this example we are using the font awesome library available in the selector page for rendering a nice [icon](https://fontawesome.com/v5/search?q=pizza&o=r&m=free) but we could have used any other thing here like an `img` tag, for instance.

Ensure to properly escape double quotes if necessary. Also make the markup a one-liner: JSON strings cannot span several lines.

Expand Down
8 changes: 5 additions & 3 deletions docs/casa/developer/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Acquaintance with the following technologies is recommended:
### Sample plugins

The best way to start learning Casa plugin development is by playing with the sample plugins you can find [here](
https://github.com/JanssenProject/jans/tree/vreplace-janssen-version/jans-casa/plugins/samples). Clone the repository ( a shallow clone of `main` branch is fine), `cd` to one of the directories in the folder and run `mvn package`, then upload the resulting `jar-with-dependencies` through the administration console.
https://github.com/JanssenProject/jans/tree/vreplace-janssen-version/jans-casa/plugins/samples). Clone the repository (a shallow clone of `main` branch is fine), `cd` to one of the directories in the folder and run `mvn package`, then upload the resulting `jar-with-dependencies` through the administration console.

## Configuration management

Expand Down Expand Up @@ -93,14 +93,16 @@ Extract [the Agama project](https://maven.jans.io/maven/io/jans/casa-agama/repla

### Page customizations

The UI pages of the default Casa flow resemble the design of the Casa app itself. Also, modifications applied through the "custom branding" functionalities are automatically reflected in flow pages without any sort of intervention. This is neat, but if you need radical changes, you will have to code the UI pages your own based on the existing ones.
The UI pages of the default Casa flow resemble the design of the Casa app itself. Also, modifications applied through the "custom branding" functionalities are automatically reflected in flow pages without any sort of intervention. This is neat, but if you need to go further, you will have to code the UI pages your own based on the existing ones.

For this purpose, create a new Agama project with one flow in it. Pick one of the pages you want to change from the original project and build your own - initially keep it really simple: a dummy page is OK. From your new flow, use the `Trigger` directive to launch `io.jans.casa.authn.main` found in the original project. Add an `Override templates` directive to your `Trigger` so the page in Casa project is superseded by the page you are creating. This is explained [here](../../janssen-server/developer/agama/advanced-usages.md#template-overrides).
For this purpose, create a new Agama project with one flow in it. Pick one of the pages you want to change from the original project and build your own - initially keep it really simple: a dummy page is OK. From your new flow, use the `Trigger` directive to launch flow `io.jans.casa.authn.main`. Add an `Override templates` directive to your `Trigger` so the page in Casa project is superseded by the page you are creating. This is explained [here](../../janssen-server/developer/agama/advanced-usages.md#template-overrides).

Pack your new project and deploy it. Wait for around 30 seconds and try to log into Casa to see the changes. Note you have to configure casa so your flow is launched, not the default one, ie. `io.jans.casa.authn.main`. This was explained [earlier](#casa-acr-update).

Do as many changes as needed to your page. Then pick another page to alter and feed your `Override templates` accordingly. Repeat until your are done. Recall there is no need to restart `jans-auth` or `casa`.

In some cases, the original look-and-feel may be satisfying but it's the text content what you would like to change. Agama engine supports localization and internationalization as explained [here](../../janssen-server/developer/agama/advanced-usages.md#localization-and-internationalization) so you can supply translated messages in your own project and make templates use those. Note Casa is only bundled with a set of "default" labels out-of-the box and thus pages don't change content regardless of browser's language or location. By overriding templates and providing labels in several languages, you can achieve full localization/internationalization in the authentication UI.

### Support more authentication methods

This is probably the most common requirement. Visit this [page](./add-authn-methods.md) to learn more.
Expand Down
4 changes: 2 additions & 2 deletions docs/casa/plugins/email-otp.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ The SMTP configuration must be previously populated in the Jans Server. For this
- `subject`: Subject to use in e-mail messages. You can use `%s` as a placeholder to insert the value of the generated OTP
- `message`: Body of e-mail messages. You can use `%s` as a placeholder to insert the value of the generated OTP. Basic HTML markup is supported; ensure to properly escape characters like double quotes - keep in mind this is JSON content

1. Parameterize the `casa` project: in the `casa` project configuration, locate the `selector` section under `io.jans.casa.authn.main` flow and add an entry with key `io.jans.casa.authn.emailotp`. Assign an icon and a short descriptive text. Example:
1. Parameterize the `casa` project: in the `casa` project configuration, locate the `selector` section under `io.jans.casa.authn.main` flow and add an entry with key `io.jans.casa.authn.emailotp`. Assign an icon and a pointer to a short descriptive text. Example:

```
...
"io.jans.casa.authn.emailotp": {
"icon": "<i class='fas fa-envelope' data-fa-transform='shrink-1'></i>",
"text": "A code sent to my e-mail address"
"textKey": "email2fa.selector_text"
}
...
```
Expand Down
8 changes: 4 additions & 4 deletions jans-casa/agama/project/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,19 @@
"selector": {
"io.jans.casa.authn.otp": {
"icon": "<i class='fas fa-qrcode'></i>",
"text": "A verification code from my OTP mobile app or hardware token"
"textKey": "casa.selector.otp"
},
"io.jans.casa.authn.twilio_sms": {
"icon": "<i class='fas fa-sms'></i>",
"text": "A verification code sent to my phone via text message"
"textKey": "casa.selector.twilio"
},
"io.jans.casa.authn.fido2": {
"icon": "<span class='fa-layers fa-fw' style='bottom:-.6rem;left:-.4rem'><i class='fas fa-tablet' data-fa-transform='shrink-1'></i><i class='fas fa-mobile-alt' data-fa-transform='up-7 shrink-4'></i><i class='fas fa-stream' data-fa-transform='rotate--90 up-9 shrink-12'></i></span>",
"text": "My Fido device (eg. security key)"
"textKey": "casa.selector.fido"
},
"io.jans.casa.authn.super_gluu": {
"icon": "<i class='far fa-bell' data-fa-transform='shrink-1'></i>",
"text": "A notification to my Super Gluu"
"textKey": "casa.selector.sg"
}
}
},
Expand Down
12 changes: 6 additions & 6 deletions jans-casa/agama/project/web/authn/code.ftlh
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,27 @@

<section class="pa4 shadow-4 bg-blank gray cust-section">

<h2 class="f3 dark-blue2">2-step verification</h2>
<h2 class="f3 dark-blue2">${labels("casa.2fa_verification")}</h2>

<#if !(matches!true)>
<p class="mw5 dark-red tc pv2 ph0 ma0 f6">Wrong code entered</p>
<p class="mw5 dark-red tc pv2 ph0 ma0 f6">${labels("casa.otp.wrong")}</p>
</#if>

<div class="flex flex-column items-center pa3">
<img src="${webCtx.contextPath}/img/ver_code.png" />
<div class="db w5 tc f7-cust">Get a verification code from your OTP mobile app or hardware token</div>
<div class="db w5 tc f7-cust">${labels("casa.otp.title")}</div>
</div>

<form method="post" enctype="application/x-www-form-urlencoded" class="pt2">
<div class="relative w5 mt1 pb2">
<input type="text" class="focused-text w-100 pb1 dark-gray" id="passcode" name="passcode"
<input type="text" class="focused-text w-100 pb1 dark-gray" name="passcode"
pattern="[0-9]+" autocomplete="off" required autofocus>
<#-- Pressing the enter key on this field triggers submission via the FIRST submit button found in the page -->
<label class="focused-label-big">Enter code</label>
<label class="focused-label-big">${labels("casa.otp.enter")}</label>
</div>
<div class="flex justify-end mt2">
<input type="submit" class="f7-cust bw0 br1 ph4 pv2 bg-bsgreen-success white hover-bsgreen-success hover-white cust-primary-button"
value="Login">
value="${labels("casa.login")}">
</div>
</form>

Expand Down
16 changes: 8 additions & 8 deletions jans-casa/agama/project/web/authn/fido-authn.ftlh
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function startAssertion() {

let request = ${assertion?no_esc}
setError("")
setStatus("Please wait...")
setStatus("${labels("casa.fido.wait")?no_esc}")

webauthn.getAssertion(request)
.then(data => {
Expand All @@ -36,11 +36,11 @@ function startAssertion() {

if (name === "NotAllowedError") {
//Credential not recognized.
message = "Please use a fido credential already associated to your account"
message = "${labels("casa.fido.notAllowed")?no_esc}"
} else if (name === "AbortError") {
message = "Operation was cancelled"
message = "${labels("casa.fido.abort")?no_esc}"
} else {
message = "An error occurred"
message = "${labels("casa.fido.error")?no_esc}"

if (err.message) {
console.log(err.message)
Expand All @@ -61,20 +61,20 @@ window.onload = (event) => {
</script>

<section class="pa4 shadow-4 bg-blank gray cust-section">
<h2 class="f3 dark-blue2">2-step verification</h2>
<h2 class="f3 dark-blue2">${labels("casa.2fa_verification")}</h2>

<div class="tc f7 mt2" id="status"></div>

<div class="mw5 dark-red pv3 ph0 ma0 f7-cust" id="error"></div>

<div class="tc green hover-green f7-cust pl3 dn" id="retry">
<a href="javascript:startAssertion()" class="btn-link link-secondary">Retry security key</a>
<a href="javascript:startAssertion()" class="btn-link link-secondary">${labels("casa.fido.retry")}</a>
</div>

<div class="flex flex-column items-center pa3">
<p class="f4 tc">Insert your security key</p>
<p class="f4 tc">${labels("casa.fido.insert")}</p>
<img class="w4" src="${webCtx.contextPath}/img/securitykey.jpg" />
<div class="db w5 tc f7-cust pv3">If your key has a button, tap it. Otherwise you can remove it and re-insert it</div>
<div class="db w5 tc f7-cust pv3">${labels("casa.fido.tap_reinsert")}</div>
</div>

<form method="post" enctype="application/x-www-form-urlencoded">
Expand Down
8 changes: 4 additions & 4 deletions jans-casa/agama/project/web/authn/sg/code-scan.ftlh
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ function onSignInCallback(result) {
document.forms[0].submit()
} else {
if (result == "error") {
setError("An error has occurred")
setError("${labels("casa.sg.error")?no_esc}")
}
timeLeft = 1
$("#timer").html("")
Expand All @@ -85,15 +85,15 @@ window.onload = (event) => {

<section class="pa4 shadow-4 bg-blank gray cust-section">

<h2 class="f3 dark-blue2">Scan the QR code with your Super Gluu</h2>
<h2 class="f3 dark-blue2">${labels("casa.sg.scanQR")}</h2>

<div class="tc mb2 pt2" id="qr_container"></div>

<div class="mw5 dark-red tc pv2 ph0 mt3 f6" id="error"></div>

<div class="tc mb3 dark-blue" id="timer">Time remaining: <span id="time">-</span> secs</div>
<div class="tc mb3 dark-blue" id="timer">${labels("casa.sg.remaining")} <span id="time">-</span> ${labels("casa.sg.secondsAbbr")}</div>

<p class="tc f6 mb4">We'll log you in as soon as we detect your approval.</p>
<p class="tc f6 mb4">${labels("casa.sg.waitAuthn2")}</p>

<form method="post" enctype="application/x-www-form-urlencoded">
</form>
Expand Down
14 changes: 6 additions & 8 deletions jans-casa/agama/project/web/authn/sg/notification.ftlh
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ function onSignInCallback(result) {
if (result == "success") {
document.forms[0].submit()
} else {
let msg = "An error occurred"
let msg = "${labels("casa.sg.error")?no_esc}"
if (result == "timeout") {
msg = "We couldn't detect approval of the notification sent"
msg = "${labels("casa.sg.timeout")?no_esc}"
}
setError(msg/* + ". Try the links below for alternatives"*/)
}
Expand All @@ -36,20 +36,18 @@ window.onload = (event) => {

<section class="pa4 shadow-4 bg-blank gray cust-section">

<h2 class="f4 dark-blue2">A notification to your Super Gluu was sent</h2>
<h2 class="f4 dark-blue2">${labels("casa.sg.sent")}</h2>

<p class="tc dark-red pv2 ph0 ma0 f7-cust" id="error"></p>

<div align="center" class="mb4"><img class="w-25" src="sg.jpg"></div>

<form method="post" enctype="application/x-www-form-urlencoded">
<p class="f6">You will be authenticated once you tap &quot;approve&quot; in the <br>
notification screen.
</p>
<p class="f6">${labels("casa.sg.waitAuthn1")?no_esc}</p>
<p class="f6 mb4">
Didn't receive a notification?&nbsp;
${labels("casa.sg.noNotification")}&nbsp;
<button type="submit" name="scan-QR"
class="pa0 bw0 br0 blue hover-dark-blue underline-hover bg-transparent cust-link-button f7-cust">Scan a QR code instead</button>
class="pa0 bw0 br0 blue hover-dark-blue underline-hover bg-transparent cust-link-button f7-cust">${labels("casa.sg.scanQRInstead")}</button>
</p>
</form>

Expand Down
10 changes: 5 additions & 5 deletions jans-casa/agama/project/web/authn/sms.ftlh
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

<section class="pa4 shadow-4 bg-blank gray cust-section">

<h2 class="f3 dark-blue2">2-step verification</h2>
<h2 class="f3 dark-blue2">${labels("casa.2fa_verification")}</h2>

<#if !(matches!true)>
<p class="mw5 dark-red tc pv2 ph0 ma0 f6">Wrong code entered</p>
<p class="mw5 dark-red tc pv2 ph0 ma0 f6">${labels("casa.sms.wrong")}</p>
</#if>

<div class="flex justify-center pa3">
Expand All @@ -16,14 +16,14 @@

<form method="post" enctype="application/x-www-form-urlencoded" class="pt2">
<div class="relative w5 mt2 pb2">
<input type="text" class="focused-text w-100 pb1 dark-gray" id="passcode" name="passcode"
<input type="text" class="focused-text w-100 pb1 dark-gray" name="passcode"
pattern="[0-9]+" autocomplete="off" required autofocus>
<#-- Pressing the enter key on this field triggers submission via the FIRST submit button found in the page -->
<label class="focused-label-big">Enter the code sent via SMS</label>
<label class="focused-label-big">${labels("casa.sms.enter")}</label>
</div>
<div class="flex justify-end mt2">
<input type="submit" class="f7-cust bw0 br1 ph4 pv2 bg-bsgreen-success white hover-bsgreen-success hover-white cust-primary-button"
value="Login">
value="${labels("casa.login")}">
</div>
</form>

Expand Down
6 changes: 3 additions & 3 deletions jans-casa/agama/project/web/authn/sms_prompt.ftlh
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

<section class="pa4 shadow-4 bg-blank gray cust-section">

<h2 class="f3 dark-blue2">2-step verification</h2>
<h2 class="f3 dark-blue2">${labels("casa.2fa_verification")}</h2>

<div class="flex flex-column justify-center items-center pa3">
<img src="${webCtx.contextPath}/img/phone-ver.png" />
<span class="db w5 tc f7-cust pt2">Choose a number to send an SMS to:</span>
<span class="db w5 tc f7-cust pt2">${labels("casa.sms.choose")}</span>
</div>

<form method="post" enctype="application/x-www-form-urlencoded">
Expand All @@ -26,7 +26,7 @@

<div class="flex justify-end mt2">
<input type="submit" class="f7-cust bw0 br1 ph4 pv2 bg-bsgreen-success white hover-bsgreen-success hover-white cust-primary-button"
value="Send">
value="${labels("casa.sms.send")}">
</div>
</form>

Expand Down
6 changes: 3 additions & 3 deletions jans-casa/agama/project/web/commons.ftlh
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
<!-- grow horizontally and vertically as much as possible -->
<div class="flex flex-column justify-between w-100 h-100">
<div class="flex flex-column items-center justify-center w-100 h-100 mv4">
<noscript><p class="red">Please enable javascript to use this page!</p></noscript>
<noscript><p class="red">${labels("casa.enableJS")}</p></noscript>

<#nested>

Expand All @@ -79,10 +79,10 @@

<form method="post" enctype="application/x-www-form-urlencoded">
<div class="flex flex-column items-center pt3 mt2">
<span class="f7">Stuck or changed your mind?</span>
<span class="f7">${labels("casa.stuck_authn")}</span>
<button class="f7-cust pa0 bw0 br0 blue hover-dark-blue underline-hover bg-transparent cust-link-button"
type="submit" id="skipped" name="skipped" value="">
Use a different authentication method
${labels("casa.alternative_authn")}
</button>
</div>
</form>
Expand Down
Loading

0 comments on commit 0198c32

Please sign in to comment.