Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support input fields in shadow DOM #555

Open
madduck opened this issue Sep 16, 2023 · 9 comments
Open

Support input fields in shadow DOM #555

madduck opened this issue Sep 16, 2023 · 9 comments

Comments

@madduck
Copy link
Contributor

madduck commented Sep 16, 2023

Today I learnt about "shadow domains" or "shadow roots": https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_shadow_DOM

Basically, these are self-contained DOMs within a DOM. The reason I am writing about them here is that PassFF's onNodeAdded function uses document.getElementsByTagName('input') to enumerate the input fields, but this does not include fields in shadow domains.

And this is by design: it is not possible to access elements within a shadow root programmatically, like one would select elements in the DOM.

The workaround is code like https://stackoverflow.com/a/71692555 or more explicit:

function* descend(el, sel, parent) {
        if (el.matches(sel)) {
            yield parent ? el.parentElement : el;
        }
        if (el.shadowRoot) {
            for (const child of el.shadowRoot.children) {
                yield* descend(child, sel, parent);
            }
        }
        for (const child of el.children) {
            yield* descend(child, sel, parent);
        }
    };

instead of the current use of document.getElementsByTagName. To make it a bit more efficient, the recursive function could return input and select in the same run.

If you'd consider going down this path (haha), then I could make a PR…

@tuxor1337
Copy link
Collaborator

I would assume that the native document.getElementsByTagName is much more efficient than reimplementing the functionality. I don't see why we would want to take this performance risk unless more than 50% of the login forms use this kind of encapsulation. So far, I haven't see a single login form that would profit from this.

@madduck
Copy link
Contributor Author

madduck commented Sep 18, 2023

I agree that document.getElementsByTagName probably has access to a hash of sorts and can do the search in O(log n) time, rather than O(n), but I have no evidence of that. Obviously, I'd like to avoid the complexity increase too.

However, from all I've read, shadow roots are The Future™, and we'll see more of them as more modern web applications join the rounds.

For now, I've also only ever encountered it once, but it's for the login of "meta login" app Authentik, which is a broker between different authentication mechanisms, like Keycloak, and very cool and fresh.

You can see the shadow root in action here: https://customers.goauthentik.io/l/support

Rather than reimplementing the tree walk, I wonder if there's a heuristic or a site flag we can use. I wouldn't mind having to flag sites where PassFF needs to do its own recursive search, but I am not sure where to store such data.

One idea might be to try the search if the user explicitly asks PassFF to fill in a form, but document.getElementsByTagName returns nothing. I wouldn't do that just to display the (P) symbols on page load, though. But if PassFF manages to find a form that way, then maybe it can remember the site to be one of those shadow-ey ones?

@tuxor1337
Copy link
Collaborator

Thanks for the elaboration!

You can see the shadow root in action here: https://customers.goauthentik.io/l/support

It seems to me like the form is correctly parsed by PassFF...?

Your proposed solution seems to be okay, but considering its complexity, I would not add this functionality to PassFF unless there is a substantial amount of cases where it is actually required.

@madduck
Copy link
Contributor Author

madduck commented Sep 19, 2023

I provided a bad example, as Authentik uses an older or different code base of their own code it seems. See https://sso.toni.immo for a cutting-edge example.

How about we leave this issue open for now, maybe with a different label, and see how much interest it generates? And then we decide whether to touch the code?

@madduck
Copy link
Contributor Author

madduck commented Sep 19, 2023

I was just informed that at least for Authentik, there is a per-flow configuration switch to enable "compatibility mode":

image

This turns off the use of shadow roots and makes PassFF work. So Authentik considers PassFF to be an outdated tool for which compatibility mode is required. :)

@tuxor1337 tuxor1337 changed the title Input fields in shadow domains are not enumerated Support input fields in shadow DOM Sep 19, 2023
@tuxor1337
Copy link
Collaborator

As far as I can see, the login forms mentioned here are not really affected by this. Can you maybe link to a login form that is currently affected by this?

@madduck
Copy link
Contributor Author

madduck commented May 22, 2024

That is correct, we enabled "backward compatibility" to disable the use of shadow DOMs. Have a look at https://sso.krafftwerk.de as soon as you can, and then please let me know so I can revert the change again.

@tuxor1337
Copy link
Collaborator

tuxor1337 commented May 22, 2024

Thanks! I had a look, so feel free to revert the change again. It would of course be better to have an example that is permanently accessible for testing purposes. I even think that this issue is rather low priority as long as there are no actual examples of this out there.

@madduck
Copy link
Contributor Author

madduck commented May 22, 2024

Well, I agree. The difficulty is that this is a modern security extension of browsing/websites, as far as I understand. It's common in open-source like Authentik, but probably won't be in commercial products, at least not for a while. It is an interesting HTML concept, I thought. But yeah, seems like it's probably best in the "too-hard basket" for now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants