auth::authenticate (public)

 auth::authenticate [ -return_url return_url ] \
    [ -authority_id authority_id ] [ -username username ] \
    [ -email email ] -password password [ -persistent ] [ -no_cookie ] \
    [ -first_names first_names ] [ -last_name last_name ] \
    [ -host_node_id host_node_id ]

Defined in packages/acs-authentication/tcl/authentication-procs.tcl

Try to authenticate and login the user forever by validating the username/password combination, and return authentication and account status codes.

Switches:
-return_url
(optional)
If specified, this can be included in account status messages.
-authority_id
(optional)
The ID of the authority to ask to verify the user. Defaults to local authority.
-username
(optional)
Authority specific username of the user.
-email
(optional)
User's email address. You must supply either username or email.
-password
(required)
The password as the user entered it.
-persistent
(boolean) (optional)
Set this if you want a permanent login cookie
-no_cookie
(boolean) (optional)
Set this if you don't want to issue a login cookie
-first_names
(optional)
-last_name
(optional)
-host_node_id
(optional)
Optional parameter used to determine the cookie domain from the host_node_map
Returns:
Array list with the following entries:
  • auth_status: Whether authentication succeeded. ok, no_account, bad_password, auth_error, failed_to_connect
  • auth_message: Human-readable message about what went wrong. Guaranteed to be set if auth_status is not ok. Should be ignored if auth_status is ok. May contain HTML.
  • account_status: Account status from authentication server. ok, closed.
  • account_url: A URL to redirect the user to. Could e.g. ask the user to update his password.
  • account_message: Human-readable message about account status. Guaranteed to be set if auth_status is not ok and account_url is empty. If nonempty, must be relayed to the user regardless of account_status. May contain HTML. This proc is responsible for concatenating any remote and/or local account messages into one single message which can be displayed to the user.
  • user_id: Set to local user_id if auth_status is ok.

Partial Call Graph (max 5 caller/called nodes):
%3 test_auth_authenticate auth_authenticate (test acs-authentication) auth::authenticate auth::authenticate test_auth_authenticate->auth::authenticate test_auth_use_email_for_login_p auth_use_email_for_login_p (test acs-authentication) test_auth_use_email_for_login_p->auth::authenticate _ _ (public) auth::authenticate->_ acs_user::get_user_info acs_user::get_user_info (public) auth::authenticate->acs_user::get_user_info acs_user::registered_user_p acs_user::registered_user_p (public) auth::authenticate->acs_user::registered_user_p ad_conn ad_conn (public) auth::authenticate->ad_conn ad_log ad_log (public) auth::authenticate->ad_log http_auth::set_user_id http_auth::set_user_id (public) http_auth::set_user_id->auth::authenticate oacs_dav::set_user_id oacs_dav::set_user_id (public) oacs_dav::set_user_id->auth::authenticate packages/acs-subsite/lib/login.tcl packages/acs-subsite/ lib/login.tcl packages/acs-subsite/lib/login.tcl->auth::authenticate packages/acs-subsite/www/register/auto-login.tcl packages/acs-subsite/ www/register/auto-login.tcl packages/acs-subsite/www/register/auto-login.tcl->auth::authenticate packages/acs-subsite/www/user/password-update.tcl packages/acs-subsite/ www/user/password-update.tcl packages/acs-subsite/www/user/password-update.tcl->auth::authenticate

Testcases:
auth_authenticate, auth_use_email_for_login_p
Source code:

    # Login Brute Force Prevention
    set login_attempt_key "[ad_conn peeraddr]-[ad_conn subsite_id]"

    if { [::auth::login_attempts::threshold_reached_p -login_attempt_key $login_attempt_key] } {
        set auth_message [_ acs-authentication.Too_many_failed_login_attempts]

        return [list auth_status "failed_to_connect"  auth_message $auth_message  account_status "closed"  account_message "[_ acs-subsite.Auth_internal_error]"]
    }

    # record login attempt
    ::auth::login_attempts::record -login_attempt_key $login_attempt_key

    if { $username eq "" } {
        if { $email eq "" } {
            set result(auth_status) "auth_error"
            if { [auth::UseEmailForLoginP] } {
                set result(auth_message) [_ acs-subsite.Email_required]
            } else {
                set result(auth_message) [_ acs-subsite.Username_required]
            }
            return [array get result]
        }
        set user_id [party::get_by_email -email $email]
        if { $user_id eq "" || ![acs_user::registered_user_p -user_id $user_id] } {
            set result(auth_status) "no_account"
            set result(auth_message) [_ acs-subsite.Unknown_email]
            return [array get result]
        }
        set user [acs_user::get_user_info -user_id $user_id]
        set authority_id [dict get $user authority_id]
        set username     [dict get $user username]
    } else {
        # Default to local authority
        if { $authority_id eq "" } {
            set authority_id [auth::authority::local]
        }
    }

    #
    # initialize result with authentication and account keys
    #
    array set result {auth_status "n/a" auth_message "" account_status "n/a" account_message ""}

    ad_try {
        array set result [auth::authentication::authenticate  -username $username  -authority_id $authority_id  -password $password]

    } on error {errorMsg} {
        set result(auth_status) failed_to_connect
        set result(auth_message) $errorMsg
        ad_log Error "auth::authenticate: error '$errorMsg' invoking authentication driver for authority_id = $authority_id: $::errorInfo"
    }

    # Returns:
    #   result(auth_status)
    #   result(auth_message)
    #   result(account_status)
    #   result(account_message)

    # Verify result/auth_message return codes
    switch $result(auth_status) {
        ok {
            # reset/unset failed login attempts counter after a successful authentication
            ::auth::login_attempts::reset -login_attempt_key $login_attempt_key

            # Continue below
        }
        no_account -
        bad_password -
        auth_error -
        failed_to_connect {
            if { $result(auth_message) eq "" } {
                array set default_auth_message {
                    no_account {Unknown username}
                    bad_password {Bad password}
                    auth_error {Invalid username/password}
                    failed_to_connect {Error communicating with authentication server}
                }
                set result(auth_message) $default_auth_message($result(auth_status))
            }
            return [array get result]
        }
        default {
            ns_log Error "auth::authenticate: Illegal auth_status code '$result(auth_status)' returned from authentication driver for authority_id $authority_id ([auth::authority::get_element -authority_id $authority_id -element pretty_name])"

            set result(auth_status) "failed_to_connect"
            set result(auth_message) [_ acs-subsite.Auth_internal_error]
            return [array get result]
        }
    }

    # Verify remote account_info/account_message return codes
    switch $result(account_status) {
        ok {
            # Continue below
        }
        closed {
            if { $result(account_message) eq "" } {
                set result(account_message) [_ acs-subsite.Account_not_avail_now]
            }
        }
        default {
            ns_log Error "auth::authenticate: Illegal account_status code '$result(account_status)' returned from authentication driver for authority_id $authority_id ([auth::authority::get_element -authority_id $authority_id -element pretty_name])"

            set result(account_status) "closed"
            set result(account_message) [_ acs-subsite.Auth_internal_error]
        }
    }

    #
    # Save the remote account information for later
    #
    set remote_account_status $result(account_status)
    set remote_account_message $result(account_message)

    #
    # Clear out remote account_status and account_message
    # and initialize it with values that we can relay on later.
    #
    array set result {account_url "" account_status "" account_message ""  user_id ""}

    # Map to row in local users table
    array set result [auth::get_local_account  -return_url $return_url  -username $username  -authority_id $authority_id  -email $email  -first_names $first_names  -last_name $last_name]
    # Returns:
    #   result(account_status)
    #   result(account_message)
    #   result(account_url)
    #   result(user_id)

    # Verify local account_info/account_message return codes
    switch $result(account_status) {
        ok {
            # Continue below
        }
        closed {
            if { $result(account_message) eq "" } {
                set result(account_message) [_ acs-subsite.Account_not_avail_now]
            }
        }
        default {
            ns_log Error "auth::authenticate: Illegal account_status code '$result(account_status)' returned from auth::get_local_account for authority_id $authority_id ([auth::authority::get_element -authority_id $authority_id -element pretty_name])"

            set result(account_status) "closed"
            set result(account_message) [_ acs-subsite.Auth_internal_error]
        }
    }

    # If the remote account was closed, the whole account is closed, regardless of local account status
    if {$remote_account_status eq "closed"} {
        set result(account_status) closed
    }

    if { $remote_account_message ne "" } {
        if { $result(account_message) ne "" } {
            # Concatenate local and remote account messages
            set local_account_message [auth::authority::get_element  -authority_id $authority_id  -element pretty_name]
            set result(account_message) [subst {
                <p>$local_account_message: $remote_account_message</p>
                <p>[ad_system_name]: $result(account_message)</p>
            }]
        } else {
            set result(account_message) $remote_account_message
        }
    }

    #
    # Issue login cookie if login was successful
    # and everything is ok with the account.
    #
    if { $result(auth_status) eq "ok"
         && !$no_cookie_p
         && $result(user_id) ne ""
         && $result(account_status) eq "ok"
     } {
        if {$host_node_id ne ""} {
            set cookie_domain [db_string get_mapped_host {
                select host from host_node_map where node_id = :host_node_id
            } -default ""]
            if {$cookie_domain eq ""} {
                ns_log warning "auth::authenticate: host_node_id $host_node_id was provided but is apparently not mapped"
            }
        } else {
            set cookie_domain ""
        }
        ns_log notice "auth::authenticate receives host_node_id $host_node_id domain <$cookie_domain>"
        ad_user_login  -account_status $result(account_status)  -cookie_domain $cookie_domain  -forever=$persistent_p  $result(user_id)
    }

    return [array get result]
Generic XQL file:
packages/acs-authentication/tcl/authentication-procs.xql

PostgreSQL XQL file:
packages/acs-authentication/tcl/authentication-procs-postgresql.xql

Oracle XQL file:
packages/acs-authentication/tcl/authentication-procs-oracle.xql

[ hide source ] | [ make this the default ]
Show another procedure: