goauthentik / authentik

The authentication glue you need.
https://goauthentik.io
Other
12.84k stars 852 forks source link

Additional custom flows in user settings #6413

Open NomAnor opened 1 year ago

NomAnor commented 1 year ago

Describe the solution you'd like Add a configuration option (to the tenants?) for a list of flows that are linked on the user settings page, similar to the "Change password" button.

Additional context I'm trying to use a freeradius server to authenticate wifi access by linking it to the LDAP provider and providing a custom user attribute for the NTLM password hash (mschapv2).

I created custom prompts for wifi-password and wifi-password-repat, a custom stage wifi-password-change-prompt with an expression policy that calculates the ntlm hash and adds it to the user attributes and a custom flow update-wifi-password.

What is missing is a way to let users start the flow from the settings page, similar to the "Change password" button. I don't want to add the password fields to the default-user-settings stage.

Showing these additional flows inline, like the default-user-settings-flow, would also be nice, but a simple button is enough.

nielscil commented 9 months ago

@NomAnor I'm trying the same using freeradius and authentik. Would you be willing to provide me the Freeradius config and the Authentik expression policy for the NTLM hash?

rqi14 commented 7 months ago

@NomAnor Seconded. Do you mind sharing the expression policy? Thanks!

PopcornPanda commented 1 week ago

@rqi14 @nielscil working policy for user password change (from user level) and from recovery flow:

import hashlib

def generate_ntlm_hash(password):
    """Generate an NTLM hash from the given password."""
    password_unicode = password.encode('utf-16le')
    return hashlib.new('md4', password_unicode).hexdigest()

def store_ntlm_hash(user, password):
    """Store the NTLM hash in the user's attributes."""
    if not user.attributes:
        user.attributes = {}
    user.attributes["ipaNTHash"] = generate_ntlm_hash(password)
    return user.save()

# Determine if the user is authenticated or pending
user = request.user if request.user and not request.user.is_anonymous else context.get("pending_user")

if user:
    # Extract the password from the context
    password = context.get("prompt_data", {}).get("password") or context.get("password")

    if password:
        return store_ntlm_hash(user, password)
    else:
        ak_message("There is no new password value in context")
        return False
else:
    ak_message("There is no user context")
    return False