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

Custom avatar pictures #2631

Open
moqmar opened this issue Mar 31, 2022 · 6 comments
Open

Custom avatar pictures #2631

moqmar opened this issue Mar 31, 2022 · 6 comments
Labels
enhancement/confirmed Enhancements that will be implemented in the future enhancement New feature or request pr_wanted Will eventually be fixed/implemented upstream, PRs will happily be accepted.

Comments

@moqmar
Copy link

moqmar commented Mar 31, 2022

Is your feature request related to a problem? Please describe.
I want to use neither Gravatar nor a completely custom avatar system, but rather the jpegPhoto field of LDAP, and want to be able to change that picture in the self-service.

Describe the solution you'd like
Being able to add a prompt field with a type "Attachment" and adding a corresponding LDAP property mapping.

Optionally, being able to access that attachment through the API (with configurable access control) with a link, so it can be used for AUTHENTIK_AVATARS, as well as other websites.

Also optionally, maybe a second type "Attachment (Square Image)" for a cropper? Or generally different settings for different prompt field types, so that could be a sub-setting - stuff like maximum file size, file types, etc. could be additional settings here.

Describe alternatives you've considered
I tried using a "Hidden" prompt field with the following "Help text" to show a file input instead, using a base64 Data-URI for a start:

<input type="file" accept="image/png, image/jpeg" class="pf-c-form-control" onchange="
  const hiddenInputs = [this.parentElement.previousElementSibling, this.nextElementSibling];
  if (!this.files[0]) {
    hiddenInputs[0].value = hiddenInputs[1].value = '';
  } else {
    const r = new FileReader();
    r.onload = () => (hiddenInputs[0].value = hiddenInputs[1].value = r.result);
    r.onerror = (error) => alert(error);
    r.readAsDataURL(this.files[0]);
  }">
<input type="hidden">

Issues with that:

Additional context
I'm not sure how much sense it makes to incorporate this as a separate full-fledged avatar feature, hence I suggested using a relatively simple "Attachment" field type.

Coincidentally, I'll also need other custom field types as well at some point (e.g. something as simple as a list of checkboxes, or even some more sophisticated plugins like subscription plan management), so it would be great to have some documentation on how to do that:

  • using a "Hidden" field with JavaScript doesn't work as outlined above
  • a "Static" field could work as well, but I have no idea how/if I can set the value here from JavaScript
  • the prefix of the "authentik: Locale: ..." field type suggests that it might be possible to dynamically add other field type plugins at some point, while https://github.com/goauthentik/authentik/blob/master/web/src/flows/stages/prompt/PromptStage.ts#L110 suggests that it's hardcoded - is something planned there?
  • more complex plugins that are out-of-scope for Authentik itself (like the subscription management) might also work as an "Embedded iFrame" prompt type with some way to automatically adjust width & height and set specific (limited) fields through window.postMessage.
@moqmar moqmar added the enhancement New feature or request label Mar 31, 2022
@sevmonster
Copy link
Contributor

sevmonster commented Apr 4, 2022

for some reason, it is never stored - if I change the field type to "Text" then it works correctly, but then I have an additional text field.

a "Static" field could work as well, but I have no idea how/if I can set the value here from JavaScript

It does appear to be intentional that hidden and other non-editable fields (i.e. static, read-only text) do not have their values saved; I would imagine this protects against users injecting data into fields that the flow writer likely expects to never change.

I think the best approach to this, rather than directly supply an "Attachment" prompt type, would be to instead have a "custom" type that accepts HTML and is validated in the editor to have an <input> element that authentik can grab the value of in the flow. The flow writer can then parse the values in a validation or expression policy server-side (you could do it client-side but you should never trust client data ever anyway) and write it to whatever attribute they want.

As for image processing, you can do that from Python with e.g. ImageMagick, though you might need to build your own container to include the necessary libraries; easier would to feed it through PHP or other API. I do that to update my LDAP server when saving user info since authentik does not currently support LDAP attribute writeback.

@WasserEsser
Copy link

WasserEsser commented Jun 26, 2022

This, together with #2521 (more prompt field types) and #3134 (multiple values) would really improve the self-service portal side of things. Being able to upload files, customize the fields or even define own ones should provide much more flexibility.

@sevmonster
Copy link
Contributor

What can you do with #3156? Does this solve your issue?

I haven't used them myself yet so I am curious too.

@moqmar
Copy link
Author

moqmar commented Jul 24, 2022

Sorry for the long comment, the longer I think about this the more things I notice :D

Problems with using #3156 for avatars

That PR indeed partially solves the first part, and is a good starting point, but it doesn't really make it possible to use the files as an Avatar as far as I see:

  • They can't be used in AUTHENTIK_AVATARS right now I believe
  • It seems like metadata (especially the MIME type) isn't saved, which means that it's not really possible to serve the correct headers
  • The file picker works well for something like SSH keys, but for images lacks quite some features one is used to from an avatar picker (cropping, square pictures only, etc.)
  • The files aren't sanitized at all, meaning that uploading an SVG there and using it as an Avatar could lead to JavaScript being executed (not a huge real XSS risk AFAIK, but if your computer mines Bitcoin on every page an Avatar is shown, that's not that great either)

Problems with & requirements of this issue

Actually, the more that I look into this, the more I notice that this is actually two issues in one:

  • Custom iFrame/HTML fields for more advanced functionality (like subscriptions, application-specific settings, etc.)
    • Define the code as the "placeholder"; then show it in an iFrame as a data: URL
    • Add a basic stylesheet that matches the existing Authentik UI
    • Get and set the value in the iFrame using e.g. authentik_field.value (as a getter/setter, using window.postMessage)
  • Improved and custom Avatars
    • Required: Ability to access the avatar from the outside (using an URL, e.g. .../core/users/{id}/avatar)
    • Required: Ability to use the avatar in the AUTHENTIK_AVATARS setting (e.g. by setting it to user:attributes.avatar)
    • Required: Save metadata for file fields - can they be data:-URIs maybe?
    • Recommended: Sanitizer & compressor to make the files work everywhere
    • Recommended: Ability to access the avatar from LDAP (using jpegImage), and possibly through other providers
    • Optional: Nice image cropper to choose an avatar (maybe as a separete field type, or incorporated into the "file" field)

I'd say let's keep this issue about the avatars and I'll create a new one for the custom fields.

Suggestion for AUTHENTIK_AVATARS

For the AUTHENTIK_AVATARS setting, I'd propose to make this actually a fallback-based setting: user:attributes.avatar,https://example.org/avatars/%(username)s,gravatar,data:https://example.org/default-avatar.png

That would mean "Use the avatar field first, then try fetching it from an URL, then use Gravatar if the URL returned an error, and if there's no Gravatar picture use a default avatar".

Then, the API route /core/users/{id}/avatar could act basically as a reverse proxy, which would incidentally solve some privacy issues with Gravatar as well.

Off-Topic workflow question

I have one workflow question to the Authentik maintainers: in web/package.json, there's a line "@goauthentik/api": "^2022.7.3-1658335211",, and as make web-build always runs npm ci, that means that I basically can't update the API locally at all. As a workaround for development, I removed the web-install dependency for web-build in Makefile so that make gen && make web-build works again, but would be interested in what the intended way is.

@moqmar moqmar changed the title Custom avatar pictures and custom/additional prompt types in general Custom avatar pictures Jul 24, 2022
@BeryJu
Copy link
Member

BeryJu commented Jul 26, 2022

Partial reply, bear with

Sorry for the long comment, the longer I think about this the more things I notice :D

Problems with using #3156 for avatars

That PR indeed partially solves the first part, and is a good starting point, but it doesn't really make it possible to use the files as an Avatar as far as I see:

  • They can't be used in AUTHENTIK_AVATARS right now I believe
  • It seems like metadata (especially the MIME type) isn't saved, which means that it's not really possible to serve the correct headers

the MIME type is passed to the server (as this isn't a multi-part form post, but rather just base64 encoded Data URI that is in the JSON)

  • The file picker works well for something like SSH keys, but for images lacks quite some features one is used to from an avatar picker (cropping, square pictures only, etc.)

That would be great for a supposed image field that uses the current field with a different UI

  • The files aren't sanitized at all, meaning that uploading an SVG there and using it as an Avatar could lead to JavaScript being executed (not a huge real XSS risk AFAIK, but if your computer mines Bitcoin on every page an Avatar is shown, that's not that great either)

Also true, I purposefully dont want to do any validation as that should be done with policies IMO

Suggestion for AUTHENTIK_AVATARS

For the AUTHENTIK_AVATARS setting, I'd propose to make this actually a fallback-based setting: user:attributes.avatar,https://example.org/avatars/%(username)s,gravatar,data:https://example.org/default-avatar.png

That would mean "Use the avatar field first, then try fetching it from an URL, then use Gravatar if the URL returned an error, and if there's no Gravatar picture use a default avatar".

I like the idea of this, however at that point it might as well be turned into a tenant-level setting instead of a global one

Then, the API route /core/users/{id}/avatar could act basically as a reverse proxy, which would incidentally solve some privacy issues with Gravatar as well.

Not sure how I feel about this, reverse proxying gravatar/generic-other-service would have advantages but could also be abused if not done well

Off-Topic workflow question

I have one workflow question to the Authentik maintainers: in web/package.json, there's a line "@goauthentik/api": "^2022.7.3-1658335211",, and as make web-build always runs npm ci, that means that I basically can't update the API locally at all. As a workaround for development, I removed the web-install dependency for web-build in Makefile so that make gen && make web-build works again, but would be interested in what the intended way is.

I run make gen when doing schema changes but have make web-watch running in another tab, which just rebuilds the UI with the new API client

BeryJu added a commit that referenced this issue Jul 26, 2022
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>

#2631
@moqmar
Copy link
Author

moqmar commented Oct 12, 2022

I tried various image croppers now and found Croppie.js to work very well - an image input component for Authentik (although not yet actually working) could look like this then as a UI concept:

grafik

@BeryJu BeryJu added pr_wanted Will eventually be fixed/implemented upstream, PRs will happily be accepted. enhancement/confirmed Enhancements that will be implemented in the future labels Mar 28, 2024
@BeryJu BeryJu added this to the Future release milestone Mar 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement/confirmed Enhancements that will be implemented in the future enhancement New feature or request pr_wanted Will eventually be fixed/implemented upstream, PRs will happily be accepted.
Projects
None yet
Development

No branches or pull requests

4 participants