User tests: Successful: Unsuccessful:
Joomla
helper class, replacing it with native codeWebAuth\Server
object. This adds Windows Hello support without having to update to a new major version of the third party WebAuthn libraryJoomla.getOptions
The PR replaces #37673
Please remember to run npm ci
after applying the PR — the JavaScript has changed.
Please remember to use HTTPS with a certificate trusted by your computer; WebAuthn doesn't work on plain HTTP.
Please use a relatively recent (2019 onwards) build of Chrome, Edge, Firefox etc.
Go to your user profile in the backend of the site.
Click on the ‘W3C Web Authentication (WebAuthn)’ tab.
On a Windows computer without any hardware authenticator attached click on Add New Authenticator.
The browser asks you to plug in an authenticator.
You can enter your PIN / show your face / use a fingerprint scanner to register Windows Hello as an authenticator.
Delete the authenticator and try adding it again in the user profile page in the frontend of the site. It should still work.
Make sure that in the frontend you can delete an authenticator you added in the backend.
Make sure that in the backend you can delete an authenticator you added in the frontend.
Please make sure you can add more than one authenticators. IMPORTANT! You cannot add the same authenticator twice (in the past you could; it was a bug that went unnoticed). You can only test this if you have more than one authenticators, e.g. Windows Hello, a FIDO or FIDO2 hardware authenticator, an Android phone and so on.
Please make sure that you can edit the name of the authenticator. This was broken in #37464.
Please make sure you can log into the front- and backend of the site.
Please test on as many platforms as you have: Android (works on Android 9 and later if you have a fingerprint scanner but only on Chrome as far as I know), iOS/iPadOS (both TouchID and FaceID), macOS (TouchID, if you have a MacBook Air/Pro or an iMac/Mac Studio with Apple Silicon and the Apple keyboard with a TouchID sensor) as well as various FIDO and FIDO2 authenticators. I have tested all of these and Linux EXCEPT for Android due to lack of hardware running Android (my Android phone's battery bloated, I had to decommission it before it spontaneously turned into an incendiary grenade).
The following language strings were added:
PLG_SYSTEM_WEBAUTHN_ERR_XHR_INITCREATE
PLG_SYSTEM_WEBAUTHN_FIELD_ATTESTATION_SUPPORT_DESC
PLG_SYSTEM_WEBAUTHN_FIELD_ATTESTATION_SUPPORT_LABEL
PLG_SYSTEM_WEBAUTHN_LBL_DEFAULT_AUTHENTICATOR
The following language strings were changed:
PLG_SYSTEM_WEBAUTHN_LBL_DEFAULT_AUTHENTICATOR_LABEL
As of Joomla! DEPLOY_VERSION the WebAuthn plugin has attestation enabled by default. This means that only authenticators with publicly verifiable cryptographic signatures can be registered with WebAuthn starting with this version of Joomla.
The publicly verifiable certification authorities for authenticators are retrieved from the FIDO Alliance site, namely the URL https://mds.fidoalliance.org/
.
This default setting will prevent some cheaper authenticators which are not FIDO-certified from being used with WebAuthn. Moreover, some sites may be unable to download and/or cache the root certificates from FIDO Alliance, or it might take so long that the plugin aborts the operation to prevent your site from timing out. If you encounter any problems with registering authenticators with WebAuthn please edit the plugin settings and disable the Attestation Support option.
The Attestation Support feature requires the following prerequisites to work:
https://mds.fidoalliance.org/
.administrator/cache
) must be writeable by PHP.If these prerequisites are not met the WebAuthn plugin will proceed without verifying the cryptographic signatures of the authenticators against the publicly verifiable certification authorities published by the FIDO Alliance. This is still secure — in fact far more secure than using a password and Two Factor Authentication. The only downside is that you may experience a short delay, up to 5 seconds, once a month when the plugin attempts to download the root certification authority information from the FIDO Alliance.
If your site meets all of the prerequisites except the first one you may download the information from https://mds.fidoalliance.org/
and place them in the file administrator/cache/fido.jwt
. In this case the WebAuthn plugin can operate with attestation support. This is very useful if your site is behind a firewall or disconnected from the Internet (e.g. on a high security intranet handling sensitive material). You need to remember to update this file once every month to avoid any problems.
Enabling the Attestation Support feature also allows Joomla to identify the maker and model of most FIDO2 certified authenticators. If you register an authenticator after enabling this option you will see an icon of the maker's logo next to the Authenticator Name when viewing the list of authenticators. Furthermore, registering a new authenticator will have a more user-friendly default name, e.g. “Yubikey 5Ci added on 28 April 2022, 18:00” instead of “Authenticator added on 28 April 2022, 18:00”.
If you disable the Attestation Support option the logo and the authenticator type will be hidden.
Finally, do note that authenticators added with previous versions of Joomla or while the Attestation Support feature is disabled or while the Attestation Support feature is enabled but its prerequisites not met will always be displayed as “Generic Authenticator” as the necessary information to determine the make and model of the authenticator will have not been relayed to Joomla when you registered your authenticator.
Status | New | ⇒ | Pending |
Category | ⇒ | JavaScript Repository NPM Change Layout Front End Plugins |
IMPORTANT! You cannot add the same authenticator twice (in the past you could; it was a bug that went unnoticed).
Is it really a bug if I want to use windows hello fingerprint and windows hello pin?
And if you insist it is can there be a more friendly error message please instead of
InvalidStateError: The user attempted to register an authenticator that contains one of the credentials already registered with the relying party.
@nikosdion It seems drone doesn't like your PR due to the many emojis in the description text.
@brianteeman I will look into the removal of the authenticator, I think it's the same issue as the edit button.
Regarding the authenticator, you are viewing this the wrong way. The authenticator is one and the same: Windows Hello, the platform authenticator provided by Windows. How it's unlocked — be it a PIN or a fingerprint or a face scan or a PIV card or... — is an implementation detail of the authenticator which is NOT communicated to the WebAuthn consumer (the browser). The browser asks the authenticator “yo, authenticators, gather round and tell me if you know any of these registered public keys the server sent me” and the Windows Hello authenticator replies “eeeyup, one of these were issued by me, I can unlock it with my private key, don't ask me to do that again”.
The same goes for macOS where the platform authenticator can be unlocked by TouchID or double-clicking the side button of my paired Apple Watch. The unlocking gesture I use is an implementation detail. The browsers only see “macOS platform authenticator”.
@richard67 Hahahaha! I BROKE Drone, AGAIN! It's a special talent. No worries, I will remove the Emojis.
Regarding the authenticator
I understand what you are saying just not sure i agree. If I have two computers one with fingerprint and one without then it would be useful to have both fingerprint and pin setup
... or as you know the state of my laptop the fingerprint doesnt always work so could use the pin as an alternative.
thats exactly how i login to the computer
@brianteeman This is really up to the implementation on the OS side.
Seriously, what we were doing before wouldn't change that behaviour at all. We were just not sending to the browser the list of registered public keys when asking for attestation (adding authenticators), therefore the browser couldn't ask the authenticators if they already knew about them. On assertion (login) we were sending this list. Only the first public key of each authenticator was taken into account by the authenticator itself, though. All additional keys? Ignored. You could see that if you dumped the information from the database table and checked the stored signature counter. It only ever increased in the first authenticator.
Anyway, this is a moot point not up to discussion as the WebAuthn specification mandates the corrected behaviour.
Only the first public key of each authenticator was taken into account by the authenticator itself, though. All additional keys? Ignored.
To avoid misunderstanding are you saying that on 4.1 if i setup windows hello fingerprint and then windows hello pin only the fingerprint will work as a login method? That is not my experience
You could see that if you dumped the information from the database table and checked the stored signature counter.
Which table has the counter?
As per https://developer.mozilla.org/en-US/docs/Web/API/CredentialsContainer/create
excludeCredentials
(Optional): An Array of descriptors for existing credentials. This is provided by the relying party to avoid creating new public key credentials for an existing user who already have some.
We pass the existing credentials for the user when we ask for a new attestation. Also see https://www.w3.org/TR/webauthn-2/#dom-publickeycredentialcreationoptions-excludecredentials
What will happen next is between the BROWSER and the AUTHENTICATOR(S) neither of which is under our control. That's the entire point of WebAuthn! We the Relying Party (site) know exactly jack shit about the internal workings of the Authenticator and the Client. We don't have the Authenticator's private keys, we don't know how the Authenticator interacts with the user to unlock itself for cryptographic operations, we do not care how the Client communicates with the Authenticator, we don't care how the Client decides that an Authenticator has already been used to create credentials for our Relying Party ID (our site's URL). We are oblivious to all of that by design of the WebAuthn specification itself.
If Windows Hello or any other authenticator uses multiple PRIVATE keys depending on how you unlock it, therefore rejects asserting a credential if you use the “wrong” way to interact with this Authenticator, this is not our business. We cannot and must not anticipate this as per https://www.w3.org/TR/webauthn-2/#sctn-security-considerations-rp points 4 and 5:
- The Relying Party can automatically support multiple types of user verification - for example PIN, biometrics and/or future methods - with little or no code change, and can let each user decide which they prefer to use via their choice of authenticator.
- The Relying Party does not need to store additional secrets in order to gain the above benefits.
In the end of the day, our responsibility as a Relying Party (site) begins and ends by sending the excluded credentials to the Client (browser) and letting it figure out the gory details.
very cool feature ! i will test ASAP
You could see that if you dumped the information from the database table and checked the stored signature counter.
Which table has the counter?
@brianteeman I will look into the removal of the authenticator, I think it's the same issue as the edit button.
Confirmed its the same issue and the same fix
@brianteeman The credentials are stored in #__webauthn_credentials
. However this the base64 representation of an encrypted JSON document. You should set a breakpoint at the last line of \Joomla\Plugin\System\Webauthn\CredentialRepository::findAllForUserEntity
to see what is loaded from the database. Good luck!
You are missing the point I am making about windows hello. Unless I am completely misunderstanding everything then windows hello is tied to the physical computer. So if I want to use windows hello with webauthn on both my work computer AND my home computer I need to be able to set up two instances of the windows hello authenticator. Doesnt matter if one is pin and the other fingerprint or both are fingerprint they are different because the harddware is different on the different pcs.
Brian, this is TOTALLY NOT the use case you were discussing.
Each physical device's Windows Hello is a different authenticator. Likewise, each Apple device's TouchID/FaceID is a different authenticator. You can of course register different authenticators, therefore you'd be able to register different devices.
I actually have a test site where I've registered Windows Hello, a Yubikey 4, a Yubikey 5C, a Security Key NFC, two different Security Key (old FIDO version), my iPhone's FaceID, my iPad's FaceID, and my MacBook Pro's TouchID.
What you were saying before is that on the same device Windows Hello behaves differently when unlocked by PIN and fingerprint which sounds implausible but I can't test because of lack of hardware. Regardless of how you unlock it, Windows Hello will interface the TPM (hardware or software) which has a singular, device-specific private key. I don't see why the unlock method would make it work differently; if it does, that's a problem with Microsoft's implementation. Considering that they were among the parties to help define the standard I find it implausible.
Have you actually tried with different Windows computers or are you just speculating?
ok remotely logged in to a second computer and that works fine with its own windows hello - so all good there. and I get it now.
it was the error message that really confused me and led me into the path of brainfailure and the way that windows presents its options
The user attempted to register an authenticator that contains one of the credentials already registered with the relying party.
so other than the js error everything seems to be working fine - now i have my brain in gear - and as soon as you fix that one line of js I can mark it as a successful test
Were you able to use a platform authenticator over RDP?! Windows 11 wouldn't let me do it, I had to be using a physical interface when I tried it yesterday. If that's the case I might resurrect Windows 10 on my old laptop to give this a go.
I used nomachine to connect to my remote windows 10 computer and setup windows hello pin
would it be possible instead of giving the name as "authenticator added on date" to include the name of the actual authenticator eg "windows hello authenticator added on date"
@brianteeman We do not get a human readable authenticator name. All you get is the AAGUID but we really don't want to have to trawl the Internet for all possible AAGUIDs and map them to human readable names (there is currently no registry; you have to check with each authenticator manufacturer).
ok well no harm in asking
It was a good question, one I had asked myself when I was implementing this
Labels |
Added:
NPM Resource Changed
?
|
@brianteeman @laoneo Ready for testing.
The file does have a class comment, it's lines 17 through 21. What are you talking about?
@nikosdion Brian is referring to the result of the PHP code style check of Drone: https://ci.joomla.org/joomla/joomla-cms/53685/1/6
Groan! It's not in the committed file. Let me fix that.
Let me fix that.
I would be silly if I won't let you
Apparently when I was chunking my changes into separate commits in phpStorm I forgot to click on a hunk. All right, there we go, now the DocBlock is committed.
Yep, PHPCS is happy now.
Instead of using traits, I would work here with inheritance. The traits have references to properties and functions which are not declared in the trait. So it looks for me like an abuse just for the sake of splitting the code.
@laoneo The traits are used exactly because we need to split the code into manageable chunks. Working with inheritance is a bad and far more precarious solution. The problem is that Joomla requires all of these event handlers to be in the same object. So you can either take this solution or I can make it into one supermassive class. Since I will be the one maintaining this code I can't work with a supermassive class and I choose to split it using Traits. Contorting the code in unnatural ways will just make it harder to maintain. Also, if you are using a decent IDE (such as phpStorm) it knows that the Trait is used by the extension class and it can autocomplete and type hint the properties just fine. Don't try to substitute a good IDE with a subpar code contortion solution. It will end in tears.
I will reply to everything else inline.
I have successfully tested the following
The only oddity is something that I suspect cannot be fixed as below - but marking this as successful test
if you login using an authenticator and then delete the authenticator and without saving the user try to re-add the same authenticator then it fails with the cant use the same authenticator again. Which is slightly confusing but understandable.
I have tested this item
@brianteeman I actually ran into the same issue when I was fixing the problem you reported earlier. It can be fixed and I am fixing it now. It's almost 11pm, though, so I am not sure if I will finish tonight.
Fixing that will also fix the comments @laoneo made about the manage.php file. And you know what? I might be able to inject most of the stuff he asked me to inject since the critical stuff will be going through the plugin instead of being accessed through a form object.
I have not tested this item.
@brianteeman We do not get a human readable authenticator name. All you get is the AAGUID but we really don't want to have to trawl the Internet for all possible AAGUIDs and map them to human readable names (there is currently no registry; you have to check with each authenticator manufacturer).
Did a bit of research and for the hardware keys there are only some incomplete and unofficial lists available. However for windows hello they are published and there are only 4 so at least those could be used
Windows Hello employs a variety of ways to protect user credentials. You can check which method has been used to protect a credential by consuming the AAGUID field in the attestation object returned at credential creation. The following is the list of AAGUIDs that Windows Hello may return:
Software backed authenticators
Trusted Platform Module (TPM) backed authenticators
Keeping this seperate from previous post which I wrote last night but forgot to hit save.
@brianteeman We do not get a human readable authenticator name. All you get is the AAGUID but we really don't want to have to trawl the Internet for all possible AAGUIDs and map them to human readable names (there is currently no registry; you have to check with each authenticator manufacturer).
It would appear that there is a central list now maintained by the fido alliance as a jwt blob that is updated on a monthly basis. https://fidoalliance.org/metadata/
After decoding the jwt blob I can confirm that the windows aaguid in the previous post are all present so it looks like this can be used as a trusted data source.
(prior to mds v3 i dont think this was a public data source)
Category | JavaScript Repository NPM Change Layout Front End Plugins | ⇒ | Administration Language & Strings Repository NPM Change JavaScript External Library Composer Change Layout Front End Plugins |
Okay, it's been a wild ride but I think I have things which will please both @brianteeman and @laoneo in these commits.
All the injection stuff is fixed, there are no more magic object creations that I can find. Phew.
You can now see the make and model of your authenticator as well as the logo of its manufacturer IF AND ONLY IF you add it AFTER applying the latest changes. The AAGUID is not communicated to Joomla unless we ask for full attestation which is something I added in these commits.
To implement this feature I had to enable full attestation support. This means that the authenticator signatures are also checked against the root certificates known to the FIDO Alliance (h/t to Brian for the link). This makes Joomla's WebAuthn implementation even more secure and suitable for use in some high security environments (we don't have a feature to lock down the authenticator types and/or add custom certificates which would be required in very high security applications of the government, military, financial institution etc type — then again, Joomla isn't FIPS certified so it can't be used there anyway).
You CAN of course disable the attestation support if you like as it may prevent cheaper, not certified FIDO keys from being used and/or may cause problems on some sites behind firewalls, on slow connections, on subpar server configurations and the like. While I try to fail safe in these cases the only thing I cannot do is allow an uncertified key to be used after the attestation ceremony. If you need to use this kind of keys, no problem, disable Attestation Support in the plugin options and Bob's your uncle.
There was a massive bug with U2F keys (the old FIDO keys) and Android Keys on PHP 8 in the version of the WebAuthn library we are using. Since we cannot upgrade the library I had to fork three objects from the library. I marked these @deprecated 5.0
since we can get rid of them once we upgrade the library in Joomla 5.
I have so far tried this with a small army of Yubico hardware authenticators, macOS / iOS / iPadOS built-in authenticators and Windows Hello. I have NOT tried this with Android due to lack of hardware; if you have an Android phone please do test that too.
Oof. I think that's all. Please test, test again and test some more. Since we're putting all this effort into this plugin let's do it right.
awesome work - thanks. Will do plenty of android tests tonight and report back.
@brianteeman This is not a missing image. There are never missing images. It's me doing a stupid thing and using a white background when the Windows Hello image is a white smiley face on transparent background. Shoot. Let me fix that very quickly.
Labels |
Added:
Language Change
Composer Dependency Changed
|
That should do the trick.
That did fix it but to be honest with you I would drop the image. Doesnt look great (not your fault and you're not a designer). The inline styles will trigger some people and I'm pretty sure we dont need an ALT, Title and Aria
Otherwise everything in my tests worked well. Note that I have not tested what would happen when upgrading on a site that already has authenticators
The images are those provided by the vendors ??♂️
I think it's an okay solution to displaying the authenticator type when you have full attestation, maybe not so much if you're using multiples of the same authenticator. If people really hate it we can remove it and replace it with a small piece of text under the authenticator name.
I have tested this item
Appveyor (which does the ci checks on Windows) fails. It reports problems with the composer.lock file. See https://ci.appveyor.com/project/release-joomla/joomla-cms/builds/43381337 . Any idea what the problem could be?
looks like ext-sodium is missing from the version of php on appveyor
looks like ext-sodium is missing from the version of php on appveyor
Yes, that’s one of the reported problems.
Yes, that’s one of the reported problems.
I think they are all related
I‘ll try to get someone who knows more about the test set up than I do.
Brian is right. The problem is that the Windows build machine doesn’t have Sodium.
The library it complains about is used for EdDSA support. However, our plugin disables the EdDSA algorithm for attestation and assertion (linking authenticator and logging in) unless Sodium is installed. Of course the dependency needs to be installed to be usable in runtime when server conditions permit and that — installing the dependency via Composer — is what exposed the problem with the automation.
Hey, is this, dunno, the third time I break the automation with this PR by doing something it didn’t anticipate? I have a knack for doing that. Sorry!
Brian is right.
Category | JavaScript Repository NPM Change Layout Front End Plugins Administration Language & Strings External Library Composer Change | ⇒ | Unit Tests Administration Language & Strings Repository NPM Change JavaScript External Library Composer Change Layout Front End Plugins |
@richard67 There you go! I followed the suggestion in AppVeyor's output and it's working now. Basically, I tell it to ignore the fact that a dependency requires Sodium which isn't enabled and install it anyway. This is safe as we don't actually use the code that uses Sodium in AppVeyor.
@richard67 There you go! I followed the suggestion in AppVeyor's output and it's working now. Basically, I tell it to ignore the fact that a dependency requires Sodium which isn't enabled and install it anyway. This is safe as we don't actually use the code that uses Sodium in AppVeyor.
@nikosdion I see, and I see it works. Thanks.
@brianteeman I've restored your successful test result in the issue tracker since the commit which invalidated the test count has not changed anything on the tested code but only changed the test setup, see commit d2e20ce .
Labels |
Added:
?
|
@richard67 You may want to restore Brian's test again. I fixed a bug in the (old) WebAuthn library we are using and invalidated his test.
Also, I am continuing development on this as a third party plugin since it takes a very long time to get anything included in the core
apple
format instead of the packed
format. Our very old copy of the WebAuthn library (2.x) does not support it but I just finished backporting it from version 4.x — and make it PHP 7.2 compatible. It wasn't that hard and solves the problem of WebAuthn not working properly on mobile Apple devices.All of these are features I implemented today in my copy of the plugin. I don't want to put them in this PR here as it'll get into massive scope creep, testability problems and we'll miss yet another Joomla version to ship improvements to WebAuthn. Once this PR is merged I'll do two PRs for these features. One for Apple stuff, one for the resident credentials.
I believe that this will put Joomla well ahead of any other CMS in terms of secure and easy authentication options. THE END (of passwords as means of authentication) IS NIGH!
Status | Pending | ⇒ | Closed |
Closed_Date | 0000-00-00 00:00:00 | ⇒ | 2022-05-25 16:38:21 |
Closed_By | ⇒ | nikosdion |
I am no longer interested in contributing to a project which allows toxic people to call into question my integrity as a business owner and my ability as a software developer to write working software. Good luck figuring this out by yourself.
WARNING: DO NOT EVEN TRY TO COPY MY OWN CODE (WHICH IS LICENSED UNDER GPLv3).
@nikosdion Please think it over and restore your branch and reopen this PR. If it is really like you say, do you really think one person can damage your reputation? I don’t think so. Yes, in a community driven open source project there are all kinds of people, and some are not so easy to deal with. But as long as they don’t violate CoC, what shall we do? Let me know if there is anything I can do to make you change your mind. If necessary you can contact me via the contact form on my website and we can have a talk. I want peace and I do not want to lose your expertise for the project. Am saying this as a normal contributor, not speaking for anybody else, but I am sure many others fell like I do.
@richard67 I am sorry, what?! Putting someone's integrity into question (i.e. calling someone a liar), even passively-aggressively, and attacking their experience is not a CoC violation? It's an ad hominem attack!
The same thing happened to me ten years ago when Andrew Eddie personally attacked me. The end result is that he got a bit less than a slap on the wrist and allowed to continue contributing (and abusing people) just fine while I was handed a six month ban for defending myself against an uncalled for personal attack. Unfortunately, nothing has changed in the last ten years. Victim blaming abound, toxic behaviour left unchecked, normalised and encouraged.
Let me put it this way. Would you like to work in a company where your co-workers call you a fraud and a liar? Then why do that without being paid and have this unfounded accusations levelled against you in public?! If contributions are punished then I shall not contribute.
Working my way through the tests.
When I try to remove an authenticator it fails with the following js error in the console