Index: openacs-4/packages/acs-kernel/acs-kernel.info =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-kernel/acs-kernel.info,v diff -u -r1.150.2.33 -r1.150.2.34 --- openacs-4/packages/acs-kernel/acs-kernel.info 16 Sep 2021 08:27:06 -0000 1.150.2.33 +++ openacs-4/packages/acs-kernel/acs-kernel.info 28 Sep 2021 12:46:48 -0000 1.150.2.34 @@ -9,15 +9,15 @@ f t - + OpenACS Core Team Routines and data models providing the foundation for OpenACS-based Web services. 2021-09-15 OpenACS The OpenACS kernel contains the core datamodel create and drop scripts for such things as objects, groups, parties and the supporting PL/SQL and PL/pgSQL procedures. 3 - + @@ -85,6 +85,7 @@ + Fisheye: Tag 1.1 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/oracle/upgrade/upgrade-5.10.0-5.10.1d1.sql'. Fisheye: No comparison available. Pass `N' to diff? Fisheye: Tag 1.1 refers to a dead (removed) revision in file `openacs-4/packages/acs-kernel/sql/postgresql/upgrade/upgrade-5.10.0-5.10.1d1.sql'. Fisheye: No comparison available. Pass `N' to diff? Index: openacs-4/packages/acs-tcl/acs-tcl.info =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/acs-tcl.info,v diff -u -r1.95.2.30 -r1.95.2.31 --- openacs-4/packages/acs-tcl/acs-tcl.info 16 Sep 2021 08:27:12 -0000 1.95.2.30 +++ openacs-4/packages/acs-tcl/acs-tcl.info 28 Sep 2021 12:46:47 -0000 1.95.2.31 @@ -9,7 +9,7 @@ f t - + OpenACS The Kernel Tcl API library. 2021-09-15 @@ -18,9 +18,9 @@ GPL version 2 3 - + - + Index: openacs-4/packages/acs-tcl/tcl/00-icanuse-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/00-icanuse-procs.tcl,v diff -u -r1.1.2.28 -r1.1.2.29 --- openacs-4/packages/acs-tcl/tcl/00-icanuse-procs.tcl 3 Aug 2021 19:22:00 -0000 1.1.2.28 +++ openacs-4/packages/acs-tcl/tcl/00-icanuse-procs.tcl 28 Sep 2021 12:46:48 -0000 1.1.2.29 @@ -99,6 +99,7 @@ ::acs::register_icanuse "ns_conn contentsentlength" [acs::cmd_has_subcommand ns_conn contentsentlength] ::acs::register_icanuse "ns_conn partialtimes" [acs::cmd_has_subcommand ns_conn partialtimes] ::acs::register_icanuse "ns_conn pool" [acs::cmd_has_subcommand ns_conn pool] +::acs::register_icanuse "ns_crypto::pbkdf2_hmac" {[info commands ::ns_crypto::pbkdf2_hmac] ne ""} ::acs::register_icanuse "ns_crypto::randombytes" {[info commands ::ns_crypto::randombytes] ne ""} ::acs::register_icanuse "ns_db currenthandles" [acs::cmd_has_subcommand ns_db currenthandles] ::acs::register_icanuse "ns_hash" {[info commands ::ns_hash] ne ""} Index: openacs-4/packages/acs-tcl/tcl/security-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/security-procs.tcl,v diff -u -r1.126.2.52 -r1.126.2.53 --- openacs-4/packages/acs-tcl/tcl/security-procs.tcl 30 Mar 2021 14:43:45 -0000 1.126.2.52 +++ openacs-4/packages/acs-tcl/tcl/security-procs.tcl 28 Sep 2021 12:46:48 -0000 1.126.2.53 @@ -573,7 +573,8 @@ ad_proc -public sec_change_user_auth_token { user_id } { - Change the user's auth_token, which invalidates all existing login cookies, i.e. forces user logout at the server. + Change the user's auth_token, which invalidates all existing login cookies, + i.e. forces user logout at the server. } { set auth_token [ad_generate_random_string] @@ -622,45 +623,133 @@ ad_unset_cookie -domain $cookie_domain -secure t ad_user_login_secure } +namespace eval ::security { + ad_proc -private preferred_password_hash_algorithm {} { + + Check the list of preferred password hash algorithms and the + return the best which is available (or "salted-sha1" if + nothing applies). + + @return password preferred hash algorithm + } { + + set preferences [parameter::get \ + -parameter PasswordHashAlgorithm \ + -package_id $::acs::kernel_id \ + -default "salted-sha1"] + foreach algo $preferences { + if {[info commands ::security::hash::$algo] ne ""} { + # + # This preference is available. + # + return $algo + } else { + ns_log warning "PasswordHashAlgorithm '$algo' was specified," \ + "but is not available in your setup." + } + } + # + # General fallback (only necessary for invalid parameter settings) + # + ns_log warning "No valid PasswordHashAlgorithm was specified: '$preferences'." \ + "Fall back to default." + + return "salted-sha1" + } +} + +namespace eval ::security::hash { + ad_proc -private salted-sha1 {password salt} { + + Classical OpenACS password hash algorithm. This algorithm must + be always available and is independent of the + NaviServer/AOLserver version. + + @return hex encoded password hash + + } { + set salt [string trim $salt] + return [ns_sha1 ${password}${salt}] + } + + if {[::acs::icanuse "ns_crypto::pbkdf2_hmac"]} { + ad_proc -private scram-sha-256 {password salt} { + + SCRAM hash function using sha256 as digest function. The + SCRAM hash function is PBKDF2 [RFC2898] with HMAC as the + pseudo-random function and where the output key length == + hash length. We use 15K iterations for PBKDF2 as + recommended in RFC 7677. + + @return hex encoded password hash + } { + return [::ns_crypto::pbkdf2_hmac \ + -digest sha256 \ + -iterations 15000 \ + -secret $password \ + -salt $salt] + } + } +} + ad_proc -public ad_check_password { user_id password_from_form } { - Returns 1 if the password is correct for the given user ID. + + Check if the provided password is correct. OpenACS never stores + password, but uses salted hashes for identification. Different + algorithm can be used. When the stored hash is from an other hash + algorithm, which is preferred, this function updates the password + hash automatically, but only, when the password is correct. + + @return Returns 1 if the password is correct for the given user ID. } { - set found_p [db_0or1row password_select {select password, salt from users where user_id = :user_id}] - db_release_unused_handles + set found_p [db_0or1row password_select { + select password, salt, password_hash_algorithm from users where user_id = :user_id + }] if { !$found_p } { return 0 } - set salt [string trim $salt] - - if {$password ne [ns_sha1 "$password_from_form$salt"] } { + if {$password ne [::security::hash::$password_hash_algorithm $password_from_form $salt] } { return 0 } + set preferred_hash_algorithm [security::preferred_password_hash_algorithm] + if {$preferred_hash_algorithm ne $password_hash_algorithm} { + ns_log notice "upgrade password hash for user $user_id from" \ + "$password_hash_algorithm to $preferred_hash_algorithm" + ad_change_password \ + -password_hash_algorithm $preferred_hash_algorithm \ + $user_id \ + $password_from_form + } return 1 } ad_proc -public ad_change_password { + {-password_hash_algorithm "salted-sha1"} user_id new_password } { Change the user's password } { - # In case someone wants to change the salt from now on, you can do - # this and still support old users by changing the salt below. - if { $user_id eq "" } { error "No user_id supplied" } set salt [sec_random_token] - set new_password [ns_sha1 "$new_password$salt"] - db_dml password_update {} - db_release_unused_handles + set new_password [::security::hash::$password_hash_algorithm $new_password $salt] + db_dml password_update { + update users + set password = :new_password, + salt = :salt, + password_hash_algorithm = :password_hash_algorithm, + password_changed_date = current_timestamp + where user_id = :user_id + } } ad_proc -private sec_setup_session { Index: openacs-4/packages/acs-tcl/tcl/security-procs.xql =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-tcl/tcl/security-procs.xql,v diff -u -r1.10.2.1 -r1.10.2.2 --- openacs-4/packages/acs-tcl/tcl/security-procs.xql 8 Jan 2020 17:24:47 -0000 1.10.2.1 +++ openacs-4/packages/acs-tcl/tcl/security-procs.xql 28 Sep 2021 12:46:48 -0000 1.10.2.2 @@ -24,13 +24,6 @@ - - - select password, salt from users where user_id = :user_id - - - - @@ -72,14 +65,4 @@ - - - update users - set password = :new_password, - salt = :salt, - password_changed_date = current_timestamp - where user_id = :user_id - - -