sec_handler (private)

 sec_handler

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

Reads the security cookies, setting fields in ad_conn accordingly.

Partial Call Graph (max 5 caller/called nodes):
%3 rp_filter rp_filter (private) sec_handler sec_handler rp_filter->sec_handler aa_test_running_p aa_test_running_p (public) sec_handler->aa_test_running_p aa_test_start aa_test_start (public) sec_handler->aa_test_start ad_conn ad_conn (public) sec_handler->ad_conn ad_get_cookie ad_get_cookie (public) sec_handler->ad_get_cookie ad_get_signed_cookie ad_get_signed_cookie (public) sec_handler->ad_get_signed_cookie

Testcases:
No testcase defined.
Source code:
    ns_log debug "OACS= sec_handler: enter"

    if {[info exists ::security::log(login_cookie)]} {
        foreach c [list session_id secure_token user_login user_login_secure] {
            lappend msg "$c '[ad_get_cookie [security::cookie_name $c]]'"
        }
        ns_log notice "OACS [ns_conn url] cookies: $msg"
    }

    try {

        ad_get_signed_cookie [security::cookie_name session_id]

    } trap {AD_EXCEPTION NO_COOKIE} {errorMsg} {
        #
        # We have no session cookie. Maybe we are running under
        # aa_test.
        #
        #if {[nsv_array exists aa_test]} {
        #    ns_log notice "... nsv_array logindata [nsv_get aa_test logindata logindata]"
        #    ns_log notice "... ns_conn peeraddr [ns_conn peeraddr]"
        #    ns_log notice "... dict get $logindata peeraddr [ns_conn peeraddr]"
        #}
        if {[nsv_array exists aa_test]
            && [nsv_get aa_test logindata logindata]
            && [ns_conn peeraddr] in [list [dict get $logindata peeraddr] 127.0.0.1 ::1]
        } {
            #ns_log notice logindata=$logindata
            if {[dict exists $logindata user_id]} {
                set user_id [dict get $logindata user_id]
                ad_conn -set user_id $user_id
                ad_conn -set untrusted_user_id $user_id
                ad_conn -set account_status ok
                ad_conn -set auth_level ok
                #ad_conn -set session_id [sec_allocate_session]
                set auth_level ok
                set untrusted_user_id $user_id
                aa_test_start
            }
        }
        if {![aa_test_running_p]} {
            sec_login_handler
        }

    } trap {AD_EXCEPTION INVALID_COOKIE} {errorMsg} {
        #
        # We have a session cookie, but it fails the cryptographic
        # checks.  Make sure to log the current user out and update
        # session cookie and ad_conn information.
        #
        ad_user_logout
        sec_login_handler

    } on ok {session_list} {
        #
        # The session cookie exists and is valid.
        #
        set session_data [split [lindex $session_list 0] {,}]
        set session_id              [lindex $session_data 0]
        set session_user_id         [lindex $session_data 1]
        set login_level             [lindex $session_data 2]
        set session_last_renew_time [lindex $session_data 3]

        if {![string is integer -strict $session_last_renew_time]} {
            #
            # This happens only when the session cookie is old style
            # previous to OpenACS 5.7 and does not have session review
            # time embedded. Assume cookie expired and force login
            # handler.
            #
            set session_last_renew_time 0
        }

        #
        # When the session_cookie comes from an authenticated session,
        # get login cookie as well.
        #
        set login_cookie_exists_p 0
        set persistent_login_p 0

        if {$session_user_id > 0} {
            set login_info [sec_login_read_cookie]
            if {[dict get $login_info status] eq "OK"} {

                set auth_token [dict get $login_info auth_token]

                #
                # Verify currently stored user authentication token
                # against the one on the login cookie.
                #
                if {$auth_token ne [sec_get_user_auth_token $session_user_id]} {
                    #
                    # Invalid user auth token in the login
                    # cookie. This happens e.g. when user changed
                    # their password, hence all logins on different
                    # devices must be invalidated. Make sure to log
                    # the current user out and update session cookie
                    # and ad_conn information.
                    #
                    ad_user_logout
                    sec_login_handler
                } else {
                    set login_cookie_exists_p 1
                    set persistent_login_p [dict get $login_info forever_p]
                    if {$persistent_login_p eq ""} {
                        set persistent_login_p 0
                    }
                }
            }
        }

        ::security::log timeout "login_cookie persistent_login $persistent_login_p [ns_conn url]"

        set session_expr [expr {$session_last_renew_time + [sec_session_timeout]}]

        #
        # Check for persistent logins: If the user requested a
        # persistent login, don't perform session renewing based on
        # SessionTimeout.
        #
        if {!$persistent_login_p} {
            ::security::log timeout "SessionTimeout in [expr {$session_expr - [ns_time]}] secs"
            if {$session_expr < [ns_time]} {
                ::security::log timeout "SessionTimeout reached, call sec_login_handler"
                sec_login_handler
            }
        } else {
            ::security::log timeout "SessionTimeout not checked due to persistent login"
        }

        set user_id 0
        set account_status closed

        if {$login_level > 0 && [sec_session_id_invalidated_p $session_id]} {
            #
            # Check, if the session_id was invalidated (e.g. via
            # logout).  In case, someone might be operating with
            # stolen cookies. This check required to make sure that
            # after the logout this sesson_id is not accepted anymore,
            # even when below sec_session_renew time (default 5min).
            #
            ns_log warning "downgrade login_level of user $session_user_id since session_id was invalidated"
            set login_level 0
        }

        if {$login_level > 0 && !$login_cookie_exists_p} {
            #
            # $login_level > 0 requires a login cookie. If we have no
            # login cookie, somebody tries to hack around.
            #
            set login_level 0
            ns_log warning "downgrade login_level of user $session_user_id since there is no login cookie provided"
        }

        switch -- $login_level {
            1 {
                #
                # authentication ok
                #
                set auth_level ok
                set user_id $session_user_id
                set account_status ok
            }
            2 {
                #
                # authentication ok, but account closed
                #
                set auth_level ok
            }
            default {
                #
                # login_level 0: none/expired
                #

                if { $session_user_id == 0 } {
                    set auth_level none
                } else  {
                    set auth_level expired
                }
            }
        }

        ::security::log login_cookie "Insecure session OK: session_id $session_id, session_user_id $session_user_id, auth_level $auth_level, user_id $user_id"

        #
        # We're okay for the insecure session. Check if it's also
        # secure.
        #
        if { $auth_level eq "ok"
             && ([security::secure_conn_p] || [ad_conn behind_secure_proxy_p])
         } {
            catch {
                set sec_token [split [ad_get_signed_cookie [security::cookie_name secure_token]] {,}]
                if {[lindex $sec_token 0] eq $session_id
                    && [lindex $sec_token 2] eq [ad_conn peeraddr]
                } {
                    set auth_level secure
                }
            }
            ::security::log login_cookie "Secure session checked: session_id = $session_id, session_user_id = $session_user_id, auth_level = $auth_level, user_id = $user_id"
        }

        # Setup ad_conn
        ad_conn -set session_id $session_id
        ad_conn -set untrusted_user_id $session_user_id
        ad_conn -set user_id $user_id
        ad_conn -set auth_level $auth_level
        ad_conn -set account_status $account_status

        # Reissue session cookie so session doesn't expire if the
        # renewal period has passed. This is a little tricky because
        # the cookie doesn't know about sec_session_renew; it only
        # knows about sec_session_timeout.
        # [sec_session_renew] = SessionTimeout - SessionRenew (see security-init.tcl)
        # $session_expr = PreviousSessionIssue + SessionTimeout

        ::security::log timeout "SessionRefresh in [expr {($session_expr - [sec_session_renew]) - [ns_time]}] secs"

        if {  $session_expr - [sec_session_renew] < [ns_time] } {
            sec_generate_session_id_cookie
        }
    }
    #
    # Generate a CSRF token.
    #
    security::csrf::new
Generic XQL file:
packages/acs-tcl/tcl/security-procs.xql

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

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

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