Index: openacs-4/packages/acs-core-docs/www/xml/kernel/ext-auth-design.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/kernel/ext-auth-design.xml,v diff -u -N --- openacs-4/packages/acs-core-docs/www/xml/kernel/ext-auth-design.xml 28 Oct 2003 22:07:41 -0000 1.2 +++ /dev/null 1 Jan 1970 00:00:00 -0000 @@ -1,2629 +0,0 @@ - - -%myvars; -]> - - - External Authentication Design - - - EXT-AUTH-1: Authentication and Account Status API (4 hours) - - by - -Peter -Marklund - - - - Current Design - - Procedures to support this feature have already been written by - Lars. We are using the existing procedure ad_user_login and are - deprecating ad_maybe_redirect_for_registration and making it invoke - auth::require_login. - - - Execution Story - - The auth::authenticate procedure will be called by the login page - and the auth::require_login procedure at the beginning of any - application pages that require login. - - - Tradeoffs: - - For this feature reliability and testing are the prime concerns. - - - External Design - - The authtentication API has the following public methods: - -ad_proc -public auth::require_login {} { - If the current session is not authenticated, redirect to the - login page, and aborts the current page script. - Otherwise, returns the user_id of the user logged in. - Use this in a page script to ensure that only registered and authenticated - users can execute the page, for example for posting to a forum. - @return user_id of user, if the user is logged in. Otherwise will issue an ad_script_abort. - @see ad_script_abort -} - - - - -ad_proc -public auth::authenticate { - {-authority_id ""} - {-username:required} - {-password:required} -} { - Try to authenticate and login the user forever by validating the username/password combination, - and return authentication and account status codes. - - @param authority_id The ID of the authority to ask to verify the user. Defaults to local authority. - @param username Authority specific username of the user. - @param passowrd The password as the user entered it. - -} - - - - - - Testcases - - - Procedure -auth::authenticate - - Need to stub ns_sendmail? - Test auth_status not "ok" for: - - - - Invalid password - - - - Invalid username - - - - Invalid authority - - - - - Test account_status "closed" for - - - - Member state in banned, rejected, needs approval, and -deleted. - - - - - Error handling (requires stubbing the Authenticate service -contract): - - - - The Authenticate service contract call hangs and we -should time out. Can we implement this in Tcl? - - - - The Authenticate call returns comm_error. - - - - The Authenticate call returns auth_error. - - - - The Authenticate service contract call does not return -the variables that it should - - - - - - - - Page Flow - - None - - - Data Model - - None - - - TODO - - - - Write test cases - - - - Deprecate ad_maybe_redirect_for_registration and make it -invoke auth::require_login - - - - New proc acs_user::get_by_username - - - - - - - - - EXT-AUTH-3: Account Creation API (5 hours) - - - - - EXT-AUTH-3: -Account Creation API (5 hours) - - by - -Peter -Marklund - - - - Current API - - -ad_proc ad_user_new {email first_names last_name password password_question password_answer - {url ""} {email_verified_p "t"} {member_state "approved"} {user_id ""} } { - Creates a new user in the system. The user_id can be specified as an argument to enable double click protection. - If this procedure succeeds, returns the new user_id. Otherwise, returns 0. -} - - - - - - New API - - TODO: Make a auth::create_user return values from -auth::registration::Register. - - TODO: Make the auth::create_user proc honor site-wide setting -for which external authority to create account in. Holding off on -this feature for now. - - TODO: New procs: auth::registration::get_required_attributes -auth::registration::get_optional_attributes - - -ad_proc -public auth::create_user { - {-username:required} - {-password:required} - {-first_names ""} - {-last_name ""} - {-email ""} - {-url ""} - {-secret_question ""} - {-secret_answer ""} -} { - @param authority_id The id of the authority to create the user in. Defaults to - the authority with lowest sort_order that has register_p set to true. -} { - set authorities_list [list] - - # Always register the user locally - lappend authorities_list [auth::authority::local] - # Default authority_id if none was provided - if { [empty_string_p $authority_id] } { - # Pick the first authority that can create users - set authority_id [db_string first_registering_authority { - select authority_id - from auth_authorities - where register_p = 't' - and sort_order = (select max(sort_order) - from auth_authorities - where register_p = 't' - ) - } -default ""] - if { [empty_string_p $authority_id] } { - error "No authority_id provided and could not find an authority that can create users" - } - lappend authorities_list $authority_id - } - # Register the user both with the local authority and the external one - db_transaction { - foreach authority_id $authorities_list { - auth::registration::Register \ - -authority_id $authority_id \ - -username $user_name \ - -password $password \ - -first_names $first_names \ - -last_name $last_name \ - -email $email \ - -url $url \ - -secret_question $secret_question \ - -secret_answer $secret_answer - } - } -} - - - - -ad_proc -private auth::registration::Register { - {-authority_id:required} - {-username:required} - {-password:required} - {-first_names ""} - {-last_name ""} - {-email ""} - {-url ""} - {-secret_question ""} - {-secret_answer ""} -} { - Invoke the Register service contract operation for the given authority. - @authority_id Id of the authority. Defaults to local authority. - @url Any URL (homepage) associated with the new user - @secret_question Question to ask on forgotten password - @secret_answer Answer to forgotten password question -} { - if { [empty_string_p $authority_id] } { - set authority_id [auth::authority::local] - } - # TODO: - # Implement parameters - return [acs_sc::invoke \ - -contract "auth_registration" \ - -impl [auth::authority::get_element -authority_id $authority_id -element "auth_impl_name"] \ - -operation Register \ - -call_args [list [list] \ - $username \ - $authority_id \ - $first_names \ - $last_name \ - $email \ - $url \ - $password \ - $secret_question \ - $secret_answer]] -} - - - - - - - - EXT-AUTH #4: Rewrite login & register pagse to use -APIs - - - - - EXT-AUTH -#4: Rewrite login & register pages to use APIs - - - Current Design - - Login is handled by acs-subsite/www/register/index.tcl and -user-login.tcl without use of an API. All the logic is in the -pages. - - Registration is handled by -acs-subsite/www/register/user-new.tcl. Again, all logic is in the -pages. - - - - - External Design - - We will have to rewrite the following pages: - - - User login: /register/index - - - - User registration: /register/user-add - - - - Admin: /acs-admin/users/user-add, which includes user-new -(which can then be included on other pages as well) - - - - Bulk: /acs-admin/users/user-batch-add - - - - Authentication of users is handled by the -auth::authenticate - proc and registration by the -auth::local::register proc. - - - The code to handle the login process in /register/index.tcl would -look like this: - -ad_form -name user_add -form { - {authority_id:integer(hidden)} - {username:text} - {email:text} - {password} -} -on_submit { - if { [ad_parameter UsernameIsEmail] == 't' } { - set email $username - } - array set auth_info [auth::authenticate \ - -authority_id $authority_id \ - -username $username \ - -password $password] - # Handle authentication problems - switch $auth_info(auth_status) { - ok { - # Continue below - } - bad_password { - } - no_account { - } - auth_error { - } - default { - } - } - # TODO: form builder validation of auth_status - # Handle account status - switch $auth_info(account_status) { - ok { - # Continue below - } - default { - } - } - # TODO: form builder validation of account_status - # We're logged in - ad_returnrediredt $return_url - ad_script_abort -} - - - The code to handle the registration process is in -user-new.tcl would look like this: - - -array set registratoin_info [auth::register \ - -authority_id $authority_id \ - -username $username \ - -password $password \ - -first_names $first_names \ - -last_name $last_name \ - -email $email \ - -url $url \ - -secret_question $secret_question \ - -secret_answer $secret_answer] -# Handle registration problems -switch $registratoin_info(reg_status) { - ok { - # Continue below - } - default { - } -} -# User is registered and logged in -ad_returnrediredt $return_url - - - - Page Flow - - User is redirected to /register/index.tcl if login is required - (i.e. auth::require is specified) and the login is taken care of by - user-login.tcl. If user not registered (i.e. - $auth_info(account_status) == "no_account" -), - user is redirected to user-register.tcl. - - - Error Handling - - - -<literal>auth::authenticate -</literal> - - Returns the array element auth_status, which can either be: - - - ok: login was successful, continue - - - - bad_password: Username is correct, password is wrong, -redirect to bad-password, display auth_message - - - - no_account: Username not found, redirect to user-new, -display auth_message - - - - auth_error: Authentication failed, display auth_message, -display auth_message - - - - failed_to_connect: The driver didn't return anything -meaningful, display error message - - - - - - Also account_status is returned, which can either be: - - - ok: login was successful, continue - - - - closed,permanently: account permanently closed, redirect -to account_closed, display error message - - - - No match: account_status doesn't match any of the above, -display error message - - - - - - -<literal>auth::register -</literal> - - Returns the array element reg_status, which can either be: - - - ok: Registration was successful, continue - - - - failed: Registration failed, display -reg_message - - - - No match: reg_status doesn't match any of the above, -display error message - - - - - - - Estimate - - Original estimate: - - Hours spent: - - Estimated hours remaining: - - Risk: - - - - - - - EXT-AUTH #5: -Password Management API - - - Current Design - - proc "ad_change_password" updates a user's password. - - Other password update/retrieval/reset functionality is -hard-coded in the pages. - - - - TODO - - - - Decide on generic "failed-to-connect" and "connected, but -auth server returned unknown error". - - - - Test cases - - - - - - - Execution Story - User login scenario: - - - The login page will have a link to assistance with -forgotten passwords ("Forgot your password?"). The URL of that link -is determined as follows: - - - auth_authority.forgotten_pwd_url - - - - Otherwise, if the authority's pwd mgmt driver's -CanRetrievePassword or CanRetrievePassword returns "Yes", we offer -a link to the OpenACS forgotten-password page, query vars -authority_id, maybe username. - - - - Otherwise, no forgotten password link. - - - - The OpenACS forgotten-password page may require the user -to fill in question/answer fields. These will be the OpenACS -question/answers only, we do not support question/answers from -external authentication servers. - - - - The email is reset or retrieved. The new password will be -emailed to the user, either by the driver or by the authentication -API (i.e., from one or the other side of the service -contract). - - - - User changes password scenario: - - - User visits "My Account" - - - - "My Account" will provide a link to changing the user's -password as follows: - - - If the authority has a 'change_pwd_url' defined, we'll -offer a "Change my password" link that goes there. - - - - Otherwise, if the authority driver's CanChangePassword -returns "Yes", we'll offer a "Change my password" link that goes to -the normal OpenACS change password page. - - - - Otherwise, no "Change my password" link. - - - - - The change password page will call the Password -Management API to change the password. - - - - - - - - - - - - - External Design - - -ad_proc -public auth::password::get_change_url { - {-user_id:required} -} { - Returns the URL to redirect to for changing passwords. If the - user's authority has a "change_pwd_url" set, it'll return that, - otherwise it'll return a link to /user/password-update under the - nearest subsite. - @param user_id The ID of the user whose password you want to change. - @return A URL that can be linked to for changing password. -} - -ad_proc -public auth::password::can_change_p { - {-user_id:required} -} { - Returns whether the given user change password. - This depends on the user's authority and the configuration of that authority. - - @param user_id The ID of the user whose password you want to change. - @return 1 if the user can change password, 0 otherwise. -} { - # Implementation note: - # Calls auth::password::CanChangePassword(authority_id) for the user's authority. -} -ad_proc -public auth::password::change { - {-user_id:required} - {-old_password:required} - {-new_password:required} -} { - Change the user's password. - @param user_id The ID of the user whose password you want to change. - @param old_password The current password of that user. This is required for security purposes. - - @param new_password The desired new password of the user. - @return An array list with the following entries: - <ul> - <li> password_status: "ok", "no_account", "old_password_bad", - "new_password_bad", "error" </li> - <li> password_message: A human-readable description of what - went wrong. </li> - </ul> -} { - # Implementation note - # Calls auth::password::ChangePassword(authority_id, username, old_password, new_password) for the user's authority. -} -ad_proc -public auth::password::get_forgotten_url { - {-authority_id:required} -} { - Returns the URL to redirect to for forgotten passwords. If the - user's authority has a "forgotten_pwd_url" set, it'll return that, - otherwise it'll return a link to /register/email-password under the - nearest subsite. - - @param authority_id The ID of the authority that the user is trying to log into. - @return A URL that can be linked to when the user has forgotten his/her password. -} - -ad_proc -public auth::password::can_retrieve_p { - {-authority_id:required} -} { - Returns whether the given authority can retrive forgotten passwords. - - @param authority_id The ID of the authority that the user is trying to log into. - @return 1 if the authority allows retrieving passwords, 0 otherwise. -} { - # Implementation note - # Calls auth::password::CanRetrievePassword(authority_id) for the user's authority. -} -ad_proc -public auth::password::retrieve { - {-user_id:required} -} { - Retrieve the user's password. - @param user_id The ID of the user whose password you want to retrieve. - @return An array list with the following entries: - <ul> - <li> password_status: "ok", "no_account", "not_implemented", - "error" </li> - <li> password_message: A human-readable description of what - went wrong, if password_status is not "ok". Not set if - password_status is "ok". </li> - <li> password: The retrieved password. </li> - </ul> -} { - # Implementation note - # Calls auth::password::RetrievePassword(authority_id, username) for the user's authority. -} -ad_proc -public auth::password::can_reset_p { - {-authority_id:required} -} { - Returns whether the given authority can reset forgotten passwords. - - @param authority_id The ID of the authority that the user is trying to log into. - @return 1 if the authority allows resetting passwords, 0 otherwise. -} { - # Implementation note - # Calls auth::password::CanResetPassword(authority_id) for the user's authority. -} -ad_proc -public auth::password::reset { - {-user_id:required} -} { - Reset the user's password, which means setting it to a new - randomly generated password and informing the user of that new - password. - @param user_id The ID of the user whose password you want to reset. - @return An array list with the following entries: - <ul> - <li> password_status: "ok", "no_account", "not_implemented", - "error" </li> - <li> password_message: A human-readable description of what - went wrong, if password_status is not "ok". Not set if - password_status is "ok". </li> - <li> password: The new, automatically generated password. If no - password is included in the return array, that means the new - password has already been sent to the user somehow. If it is - returned, it means that caller is responsible for informing the - user of his/her new password.</li> - </ul> -} { - # Implementation note - # Calls auth::password::ResetPassword(authority_id, username) for the user's authority. -} - - - - - Implementation -Details - - Create auth::password::CanChangePassword and friends wrappers -that take authority_id plus specific parameters for the service -contract call, finds the relevant service contract implementation, -and calls that. - - - - Error Handling - - Error codes are defined in the API stubs above. - - This API should check for bad return codes, drivers throwing -Tcl errors, and timeout, and replace with "failed-to-connect" -error. - - - - Related Stories - - #19 covers password recovery pages (and should also include -change password pages). Info about these pages belong in that -story. This section belongs there: - - Pages: - - - - acs-subsite/www/register/bad-password - - - - acs-subsite/www/register/email-password (-2, --3) - - - - acs-subsite/www/user/password-update (-2) - - - - - #29, service contract for password mgmt, will have to change -as implied by the return values of this API. - - #9, local authentication driver, should take this section -into account: - - Parameters: - - - - acs-subsite.EmailForgottenPasswordP - - - - acs-subsite.RequireQuestionForPasswordReset - - - - acs-subsite.UseCustomQuestionForPasswordReset - - - - - - - Time Tracking - - - - Design: 2 hours - - - - Estimated hours remaining: 4 hours - - - - - - - - - - EXT-AUTH -#8: Automating Batch Synchronization - - - Execution Story - - - - User goes to Administration. - - - - Visits site-wide admin pages. - - - - Link says "Authentication Management". - - - - The link goes to a list of known domains. - - - - For each domain, a page: - - - - - - - Local Authority Administration ... other stuff ... -Enable/Disable nightly batch Status of last run B: history of -previous runs (30 days?) - - - - - - - - - Tradeoffs - - Which one or two of the following are emphasised in this -design? - - - - Performance: availability and efficiency - - - - Reliability and robustness - - - - - - External Design - - - Administration - - -auth::authority::enable_batch_sync -authority_id -integer -. This API toggles the value of -batch_sync_enabled_p column in ?some_table?. Returns 1 or 0. - - - - Scheduled proc - - auth::batch_sync_sweeper -. Runs every night. Runs - through all enabled and batch-enabled authorities and calls - auth::authority::batch_sync -authority_id -integer -. - - - - Internal -Design - - Administration - -ad_proc -public auth::authority::enable_batch_sync { - -authority_id -} { - db_dml toggle_enbaled_p { - update some_table - set batch_sync_enabled_p = 't' - where authority_id = :authority_id - } -} - - - Scheduled proc: - -ad_proc -public auth::batch_sync_sweeper {} { - db_foreach select_authorities { - select authority_id - from auth_authorities - where active_p = 't' - and batch_sync_enabled_p = 't' - } { - auth::authority::batch_sync -authority_id $authority_id - } -} -ad_proc -public auth::authority::batch_sync { - -authority_id -} { - set driver [auth::get_driver -authority $authority] - acs_sc::invoke $driver Synchronize -authority $authority -} - - - - Estimate - - Original estimate: - - Hours spent: - - Estimated hours remaining: - - Risk: - - - - - - - EXT-AUTH -#9: Create Authentication drivers for Local Authority - - - External Design - - auth::authenticate - calls - auth::authentication::Authenticate - which invokes - the service contract implementation for the authority. Returns: - - - auth_status: "ok", "bad_password", "no_account", -"auth_error", "failed_to_connect" - - - - auth_message: Message to the user. - - - - account_status: "ok", "closed" - - - - account_message: Message to the user. - - - - account_status and account_message are only set if -auth_status is "ok". - - - - - - Internal Design - - -ad_proc -private auth::authentication::Authenticate { - {-authority_id ""} - {-username:required} - {-password:required} -} { - Invoke the Authenticate service contract operation for the given authority. - @param username Username of the user. - @param password The password as the user entered it. - - @param authority_id The ID of the authority to ask to verify the user. Leave blank for local authority. -} { - if { [empty_string_p $authority_id] } { - set authority_id [auth::authority::local] - } - # TODO: - # Implement parameters - return [acs_sc::invoke \ - -contract "auth_authentication" \ - -impl [auth::authority::get_element -authority_id $authority_id -element "auth_impl_name"] \ - -operation Authenticate \ - -call_args [list $username $password [list]]] -} - - - - -ad_proc -private auth::local::authentication::Authenticate { - username - password - {parameters {}} -} { - Implements the Authenticate operation of the auth_authentication - service contract for the local account implementation. -} { - array set auth_info [list] - # TODO: username = email parameter ... - set username [string tolower $username] - - set authority_id [auth::authority::local] - set account_exists_p [db_0or1row select_user_info { - select user_id - from cc_users - where username = :username - and authority_id = :authority_id - }] - - if { !$account_exists_p } { - set auth_info(auth_status) "no_account" - return [array get auth_info] - } - - if { [ad_check_password $user_id $password] } { - set auth_info(auth_status) "ok" - } else { - if { [ad_parameter EmailForgottenPasswordP] == 't' } { - set auth_info(auth_status) "bad_password" - ... display link... - } else { - set auth_info(auth_status) "bad_password" - } - return [array get auth_info] - } - # We set 'external' account status to 'ok', because the - # local account status will be checked anyways - set auth_info(account_status) ok - return [array get auth_info] -} - - - - - Estimate - - Original estimate: - - Hours spent: - - Estimated hours remaining: - - Risk: - - - - - - - EXT-AUTH -#10: Create Account Creation drivers for Local Authority - - - External Design - - auth::registration::Register - returns: - - - creation_status - - - - creation_message - - - - element_messages - - - - account_status - - - - account_message - - - - - - Internal Design - - -ad_proc -private auth::registration::Register { - {-authority_id:required} - {-username:required} - {-password:required} - {-first_names ""} - {-last_name ""} - {-email ""} - {-url ""} - {-secret_question ""} - {-secret_answer ""} - {-parameters ""} -} { - Invoke the Register service contract operation for the given authority. - -} { - if { [empty_string_p $authority_id] } { - set authority_id [auth::authority::local] - } - - return [acs_sc::invoke \ - -contract "auth_registration" \ - -impl ??? \ - -operation Register \ - -call_args [list ???]] -} - - - -ad_proc -private auth::local::registration::Register { - parameters - username - authority_id - first_names - last_name - email - url - password - secret_question - secret_answer -} { - Implements the Register operation of the auth_register - service contract for the local account implementation. -} { - array set result { - creation_status "reg_error" - creation_message {} - element_messages {} - account_status "ok" - account_message {} - } - # TODO: email = username - # TODO: Add catch - set user_id [ad_user_new \ - $email \ - $first_names \ - $last_name \ - $password \ - $question \ - $answer \ - $url \ - $email_verified_p \ - $member_state \ - "" \ - $username \ - $authority_id] - if { !$user_id } { - set result(creation_status) "fail" - set result(creation_message) "We experienced an error while trying to register an account for you." - return [array get result] - } - - # Creation succeeded - set result(creation_status) "ok" - # TODO: validate data (see user-new-2.tcl) - # TODO: double-click protection - # Get whether they requre some sort of approval - if { [parameter::get -parameter RegistrationRequiresApprovalP -default 0] } { - set member_state "needs approval" - set result(account_status) "closed" - set result(account_message) [_ acs-subsite.lt_Your_registration_is_] - } else { - set member_state "approved" - } - set notification_address [parameter::get -parameter NewRegistrationEmailAddress -default [ad_system_owner]] - if { [parameter::get -parameter RegistrationRequiresEmailVerificationP -default 0] } { - set email_verified_p "f" - set result(account_status) "closed" - set result(account_message) "[_ acs-subsite.lt_Registration_informat_1][_ acs-subsite.lt_Please_read_and_follo]" - set row_id [db_string rowid_for_email { - select rowid from users where user_id = :user_id - }] - # Send email verification email to user - set confirmation_url "[ad_url]/register/email-confirm?[export_vars { row_id }]" - with_catch errmsg { - ns_sendmail \ - $email \ - $notification_address \ - "[_ acs-subsite.lt_Welcome_to_system_nam]" \ - "[_ acs-subsite.lt_To_confirm_your_regis]" - } { - ns_returnerror "500" "$errmsg" - ns_log Warning "Error sending email verification email to $email. Error: $errmsg" - } - } else { - set email_verified_p "t" - } - # Send password/confirmail email to user - if { [parameter::get -parameter RegistrationProvidesRandomPasswordP -default 0] || \ - [parameter::get -parameter EmailRegistrationConfirmationToUserP -default 0] } { - with_catch errmsg { - ns_sendmail \ - $email \ - $notification_address \ - "[_ acs-subsite.lt_Welcome_to_system_nam]" \ - "[_ acs-subsite.lt_Thank_you_for_visitin]" - } { - ns_returnerror "500" "$errmsg" - ns_log Warning "Error sending registration confirmation to $email. Error: $errmsg" - } - } - # Notify admin on new registration - if {[ad_parameter NotifyAdminOfNewRegistrationsP "security" 0]} { - with_catch errmsg { - ns_sendmail \ - $notification_address \ - $email \ - "[_ acs-subsite.lt_New_registration_at_s]" \ - "[_ acs-subsite.lt_first_names_last_name]" - } { - ns_returnerror "500" "$errmsg" - ns_log Warning "Error sending admin notification to $notification_address. Error: $errmsg" - } - } - - return [array get result] -} - - - - - Estimate - - Original estimate: - - Hours spent: - - Estimated hours remaining: - - Risk: - - - - - - - EXT AUTH #11: Create Auth driver for PAM - - - Execution Story - - When a user authenticates against an authority which uses -PAM, the PAM authentication driver will be invoked. - - - - Tradeoffs - - Reliability, robustness, portability. - - - - External Design - - Will implement the authentication service contract. - - Parameters: Don't know. - - - - Internal Design - - Mat Kovach will implement a thread-safe ns_pam AOLserver -module in C, which will provide a Tcl interface to PAM. - - We'll write the service contract implementation in Tcl as a -wrapper for the ns_pam calls. - - - - Test Cases - - Set up authentication against /etc/passwd on cph02 and test -that we can log in with our cph02 usernames and passwords. - - Using PAM driver without having the ns_pam C module -loaded. - - - - Error Handling - - Need to catch timeouts and communications errors and pass -them on to the caller. - - - - Estimate - - Mat says: 20 hours x USD 50/hr = USD 1,000. We need to sort -out with Mat what happens if it takes him longer (or -shorter). - - Adding the service contract wrappers for authentication and -password management: 8 hours. - - - - - - - EXT -AUTH #14: Create authentication driver for LDAP - - - Status - - ON HOLD awaiting info from clients on whether we can use PAM -instead of talking directly to the LDAP server, or how we should -implement this. - - - - Execution Story - - When a user authenticates against an authority which uses -LDAP, the LDAP authentication driver will be invoked. - - - - Tradeoffs - - Reliability, robustness, portability. - - - - External Design - - Will implement the authentication service contract. - - Parameters: Don't know. - - - - Internal Design - - We'd look at the extisting ns_ldap module, or we'd find -someone to implement a new thread-safe ns_ldap AOLserver module in -C, which will provide a Tcl interface to the parts of LDAP which we -need. - - We'll write the service contract implementation in Tcl as a -wrapper for the ns_ldap calls. - - - - Test Cases - - Set up an LDAP server, and configure authentication against -that. - - Using LDAP driver without having the ns_ldap C module -loaded. - - - - Error Handling - - Need to catch timeouts and communications errors and pass -them on to the caller. - - - - Estimate - - Implementing ns_ldap: unknown. - - Adding the service contract wrappers for authentication and -password management: 8 hours. - - - - - - - EXT-AUTH-16: -Authentication Service Contract (1 hour) - - by - -Peter -Marklund - - - Already done by Lars. We should ocument which messages can/should - be HTML and which should be plain text and in general try to - document expected values of return variables more clearly. - by - -Peter -Marklund - - - - - - EXT-AUTH-17: -Account Creation Service Contract (1 hour) - - by - -Peter -Marklund - - - Already done by Lars. Todo: improve documentation of return values. - by - -Peter -Marklund - - - - - - EXT-AUTH-18: -Authority Configuration Data Model (2 hours) - - by - -Peter -Marklund - - - The table auth_authorities already exists in acs-kernel for Oracle. - We need to create the table for PostgreSQL and provide upgrade - scripts. Rename column auth_p authenticate_p for readability and - clarity? Change column name active_p to enabled_p. - TODO: new column: help_contact_text with contact information -(phone, email, etc.) to be displayed as a last resort when people -are having problems with an authority. - - -create table auth_authorities ( - authority_id integer - constraint auth_authorities_pk - primary key, - short_name varchar2(255) - constraint auth_authority_short_name_un - unique, - pretty_name varchar2(4000), - active_p char(1) default 't' - constraint auth_authority_active_p_nn - not null - constraint auth_authority_active_p_ck - check (active_p in ('t','f')), - sort_order integer not null, - -- authentication - auth_impl_id integer - constraint auth_authority_auth_impl_fk - references acs_sc_impls(impl_id), - auth_p char(1) default 't' - constraint auth_authority_auth_p_ck - check (auth_p in ('t','f')) - constraint auth_authority_auth_p_nn - not null, - -- password management - pwd_impl_id integer - constraint auth_authority_pwd_impl_fk - references acs_sc_impls(impl_id), - -- Any username in this url must be on the syntax username={username} - -- and {username} will be replaced with the real username - forgotten_pwd_url varchar2(4000), - change_pwd_url varchar2(4000), - -- registration - register_impl_id integer - constraint auth_authority_reg_impl_fk - references acs_sc_impls(impl_id), - register_p char(1) default 't' - constraint auth_authority_register_p_ck - check (register_p in ('t','f')) - constraint auth_authority_register_p_nn - not null, - register_url varchar2(4000) -); - - - - - EXT-AUTH -#19: Rewrite password recovery to use API - - - Current Design - - Password recovery is currently handled by - /register/email-password.tcl, email-password-2.tcl and - email-password-3.tcl. All logic is placed in the pages. - - - Execution Story - - - - User is prompted for login, but types in a bad -password. - - - - The CanRetrievePassword service contract is called if -retrieving passwords is allowed user is redirected to -bad-password.tcl - - - - Here the RetrievePassword service contract is called, -which returns successful_p, password, message - - - - If password is empty and successful_p is true, the -authority server has send out the verification email. - - - - If successful and password is not empty, we email the -user and ask for verification. - - - - - - External Design - - -auth::password::CanResetPassword -.Input: -driver Output: 1 or 0 - - -auth::password::ResetPassword -.Input: -username, parameters.Output: successful_p: boolean, password (or -blank, if the server sends the user its new password directly), -message: To be relayed to the user. - - -auth::password::CanRetrievePassword -.Input: -driver Output: 1 or 0 - - -auth::password::RetrievePassword -.Input: -usernameOutput: retrievable_p: boolean, message: Instruct the user -what to do if not. - - -auth::password::CanChangePassword -Input: -driverOutput:True or false. - - -auth::password::ChangePassword -Input: -username, old_password, new_passwordOutput: new_password - - The logic of bad-password will be moved into /register/index as - part of ad_form, but the logic should look like something along the - lines of: - -set user_id [ad_conn] -set authority_id [auth::authority -user_id $user_id] -set driver [auth::get_driver -authority $authority] -set retrieve_password_p [auth::password::CanRetrievePassword -driver $driver] -set reset_password_p [auth::password::CanResetPassword -driver $driver] - - If $retrieve_password_p and $reset_password_p is true, this text - will be displayed: - "If you've forgotten your password, you can -ask this server to -reset your password and email a new randomly generated password to -you -." - - And email-password, should look something like this: - -# Fetch the username. What proc should we use? -set username [auth::username] -# Reset password -auth::password::ResetPassword -username $username -set subject "[_ acs-subsite.lt_Your_forgotten_passwo]" -# SIMON: how does the password get inserted here? -# Should make use of auth::password::RetrievePassword -set body "[_ acs-subsite.lt_Please_follow_the_fol]" -# Send email -if [catch {ns_sendmail $email $system_owner $subject $body} errmsg] { - ad_return_error \ - "[_ acs-subsite.Error_sending_mail]" \ - "[_ acs-subsite.lt_Now_were_really_in_tr] -<blockquote> - <pre> - $errmsg - </pre> -</blockquote> -[_ acs-subsite.lt_when_trying_to_send_y] -<blockquote> - <pre> -[_ acs-subsite.Subject] $subject -$body - </pre> -</blockquote> -" - return -} - - We'll want to add a check for CanChangePassword in /pvt/home. - - - Estimate - - Original estimate: - - Hours spent: - - Estimated hours remaining: - - Risk: - - - - - - - EXT AUTH -#20: Login pages over HTTPS - - - Current Design - - Current login pages are over HTTP. Just bashing them to be -HTTPS has these issues: - - - - Browsers will not send cookies over HTTP that were -received over HTTPS. - - - - If images on the login page are over HTTP and not HTTPS, -browsers will warn that you're seeing unsecure items as part of a -secure web page, which is annoying and unprofessional. - - - - Browsers may also give a warning when redirecting back to -the normal pages not over HTTPS. - - - - - - Execution Story - - Beginning with a human being using a computer, describe how -the feature is triggered and what it does. As this story becomes -more detailed, move pieces to appropriate parts of the -document. - - - - Tradeoffs - - Security, Reliability and robustness. - - - - External Design - - Parameters: - - - - acs-kernel.RegisterRestrictToSSLFilters: If set to 0, we -don't restrict any URLs to HTTPs. - - - - acs-subsite.RestrictToSSL: A Tcl list of URL patterns -under the given subsite to restrict to SSL, e.g. "admin/* -register/*". Currently defaults to "admin/*". Only takes effect if -SSL is installed, and acs-kernel.RegisterRestrictToSSLFilters is -set to 1. - - - - - - To do - - - - Install SSL on a development server and integration -server. - - - - Try setting RestrictToSSL to "admin/* register/*" and -test what happens. - - - - Identify and fix issues that show up. - - - - - - Time Estimate - - Original estimate: 8 hours. - - Hours spent: 0.25 - - Estimated hours remaining: - - Risk: - - - - - - - EXT-AUTH -#24: Email on password change - - - Execution story - - User: - - - User visits /pvt/home - - - - Clicks "Change my Password" - - - - Enters password - - - - User is redirected to /pvt/home - - - - Email goes out - - - - Admin: - - - () - - - - - Internal Design - - We'll first want to check whether changing the password is allowed: - - -set user_id [ad_conn user_id] -set authority [auth::authority -user_id $user_id] -set driver [auth::get_driver -authority $authority] -set change_password_p [auth::password::CanChangePassword -driver $driver] - - If $change_password_p is true, we'll display the "Change my - password" link on /pvt/home. update-password would look something - like this: - -if {![db_0or1row select_email {}]} { - db_release_unused_handles - ad_return_error "[_ acs-subsite.lt_Couldnt_find_user_use]" "[_ acs-subsite.lt_Couldnt_find_user_use_1]" - return -} -set system_owner [ad_system_owner] -set subject "some other i18n key msg" -set body "some other i18n key msg" -# Send email -if [catch {ns_sendmail $email $system_owner $subject $body} errmsg] { - ad_return_error \ - "[_ acs-subsite.Error_sending_mail]" \ - "[_ acs-subsite.lt_Now_were_really_in_tr] -<blockquote> - <pre> - $errmsg - </pre> -</blockquote> -[_ acs-subsite.lt_when_trying_to_send_y] -<blockquote> - <pre> -[_ acs-subsite.Subject] $subject -$body - </pre> -</blockquote> -" - return -} - - - - - Estimate - - Original estimate: - - Hours spent: - - Estimated hours remaining: - - Risk: - - - - - - - EXT AUTH #25: -Password Policy - - - Current Design - - This has already been implemented on oacs-4-6 branch. - - - - Expiration of passwords: Password must be changed after a -certain number of days. No password history, though. - - - - Approval expiration: If a user is approved but doesn't -log on before a certain number of days, his approval will -expire. - - - - - - To do - - - - Merge changes from oacs-4-6 onto HEAD. (Commits made -around June 6). - - - - Sort out the upgrade script sequence. - - - - - - Time Estimate - - Original estimate: 6 hours. - - Hours spent: - - Estimated hours remaining: - - Risk: - - - - - - - Who's online list - - - Execution Story - - A page showing who has requested a page during the last 5 minutes. - Could be integrated with a chat or instant messaging service. - - - Internal Design - - We keep a record of which authenticated users have requested -pags on the site in the last x minutes (typically about 5), and -thus are considered to be currently online. We've already made the -changes necessary to security-procs.tcl to do this on an earlier -project, but haven't quite finished the work and put it back into -the tree. - - Lars? - - - Estimate - - Original estimate: - - Hours spent: - - Estimated hours remaining: - - Risk: - - - - - - - EXT -AUTH #28: Create Service Contract for Batch Sync - - - Status - - NOTE: We'll need to keep a pretty close transaction log of -any action taken during batch sync, and also offer a mechanism for -storing transactions that couldn't be completed for some reason, -e.g. email address already taken, etc., email the admin, offer a -list of transactions that failed for manual resolution by an -admin. - - - - Design To -Do/Notes - - Performance criteria: Nightly batch run should be able to -complete within 3 hours with 10,000 users. - - We'll want to design an API for an incremental or snapshot -run to call, which takes care of all the updating, logging, error -handling, emailing admins, etc. - - We need examples of how the communication would be done from -our clients. - - We might need a source/ID column in the users table to -identify where they're imported from for doing updates, -particularly if importing from multiple sources (or when some users -are local.) - - - - Current Design - - None. - - - - Execution Story - - This is executed in background thread, typically -nightly. - - There's also a link from the authority administration page to -run the batch synchronization immediately. - - The process runs like this: - - - - OpenACS retrieves a document from the enterprise server -containing user information. Example mechanisms: - - - A file is delivered to an agreed-on location in the file -system at an agreed-on point in time. - - - - OpenACS does a normal HTTP request to a remote server, -which returns the document. - - - - OpenACS does a SOAP (Web Service) request to a remote -server, which returns the document. - - - - OpenACS retrieves a file from an SMB server or an FTP -server. - - - - - - - The document will contain either the complete user list -(IMS: "snapshot"), or an incremental user list (IMS: "Event Driven" --- contains only adds, edits, updates). You could for example do a -complete transfer once a month, and incrementals every night. The -invocation should decide which type is returned. - - - - The document will be in an agreed-on format, e.g. an XML -format based on the IMS Enterprise -Specification (example -XML document - - - - - Tradeoffs - - The design should favor interoperability, reliability and -robustness. - - - - External Design - - NOTE: Do we really want to do this as service contracts? We -might be better off getting one implementation running, and only do -the service contract when we're certain what it would look -like. - - TODO: Look at how Blackboard and other systems implements -this, specifically how do they get the data out of the other -system. Which enterprise servers already support the IMS Enterprise -specification? - - TODO: Find out if Greenpeace needs an different exchange -format from IMS Enterprise, given that they're not in the -University business. - - Service contract for retrieving the document: - - - GetDocument ( - type: 0 = snapshot - 1 = incremental - since: date that you want the incremental update since? - parameters: values of implementation-specific parameters - ): document as string - Performs the request necessary to get a document containing - enterprise information. - GetParameters ( - ): list of parameters specific to this implementation. - Parameters would typically be the URL to make a request to. - - - Service contract for processing the document: - - - ProcessDocument ( - type: 0 = snapshot - 1 = incremental - since: date that you want the incremental update since? - document: the document containing either incremental or snapshot of enterprise data. - parameters: values of implementation-specific parameters - ): document as string - Processes the document and updates the OpenACS users and other tables appropriately. - GetParameters ( - ): list of parameters specific to this implementation. - Not sure what parameters would be. - - - It looks like we'll use the IMS standard for formatting of -the doucment, but not so - - - - Standards - - - - -Consolidation -before the leap; IMS Enterprise 1.1 -: This sect2 says that -IMS Enterprise 1.1 (current version) does not address the -communication model, which is critically missing for real seamless -interoperability. IMS Enterprise 2.0 will address this, but -Blackboard, who's influential in the IMS committee, is adopting -OKI's programming interrfaces for this. - - - - -IMS -and OKI, the wire and the socket - - - - - - - Page Flow - - For features with UI, a map of all pages, showing which pages -can call others, which are includeable, etc. For each page, show -all UI elements on the page (text blocks, forms, form controls). -Include administration functionality. - - - - Internal Design - - Describe key algorithms, including pseudo-code. - - - Data Model - - Describe data model changes. - - - Error Handling - - What error codes or error conditions could result? How are they - handled? - - - Upgrade - - Describe in pseudo-code how upgrade will be implemented. - - - - - EXT-AUTH-29: -Password Management Service Contract (1 hour) - - by - -Peter -Marklund - - - Already done by Lars. Todo: improve documentation of return values. - by - -Peter -Marklund - - - - - - EXT-AUTH -#30: Create Authority Management API - - - External Design - - We'll want an API that lets us - - - add authorities: auth::authority::new - - - - delete authorities: auth::authority::delete - - - - and edit authorities: auth::authority::edit - - - - authorities. - Here goes: - - - - Internal Design - - -ad_proc -public auth::authority::new { - {-authority_id:required} - {-short_name:required} - {-pretty_name:required} - {-sort_order:required} - {-auth_impl_id:required} - {-auth_p:required} - {-pwd_impl_id:required} - {-forgotten_pwd_url:required} - {-change_pwd_url:required} - {-register_impl_id:required} - {-register_p:required} - {-register_url:required} -} { - db_dml new_authority { - insert into auth_authorities ( - authority_id, - short_name, - pretty_name, - active_p, - sort_order, - auth_impl_id, - auth_p, - pwd_impl_id, - forgotten_pwd_url, - change_pwd_url, - register_impl_id, - register_p, - register_url - ) values ( - :authority_id, - :short_name, - :pretty_name, - 1, - :sort_order, - :auth_impl_id, - :auth_p, - :pwd_impl_id, - :forgotten_pwd_url, - :change_pwd_url, - :register_impl_id, - :register_p, - :register_url - ) - } -} -ad_proc -public auth::authority::delete { - {-authority_id:requied} -} { - db_exec delete_authority { - delete from auth_authorities - where authority_id = :authority_id - } -} -ad_proc -public auth::authority::edit { - {-authority_id:required} - {-short_name:required} - {-pretty_name:required} - {-active_p:required} - {-sort_order:required} - {-auth_impl_id:required} - {-auth_p:required} - {-pwd_impl_id:required} - {-forgotten_pwd_url:required} - {-change_pwd_url:required} - {-register_impl_id:required} - {-register_p:required} - {-register_url:required} -} { - db_exec edit_authority { - update auth_authorities - set short_name = :short_name, - pretty_name = :pretty_name, - active_p = :active_p, - sort_order = :sort_order, - auth_impl_id = :auth_impl_id, - auth_p = :auth_p, - pwd_impl_id = :pwd_impl_id, - forgotten_pwd_url = :forgotten_pwd_url, - change_pwd_url = :change_pwd_url, - register_impl_id = :register_impl_id, - register_p = :register_p, - register_url = :register_url - where authority_id = :authority_id - } -} - - - - - Estimate - - Original estimate: - - Hours spent: - - Estimated hours remaining: - - Risk: - - - - - - - EXT-AUTH-31: -External Authentication Datamodel (2 hours) - - by - -Peter -Marklund - - - The columns authority_id and username have been added to the users - table for Oracle. We need to add them for PostgreSQL and provide - upgrade scripts. - -create table users ( - user_id not null - constraint users_user_id_fk - references persons (person_id) - constraint users_pk primary key, - authority_id integer - constraint users_auth_authorities_fk - references auth_authorities(authority_id), - username varchar2(100) - constraint users_username_nn - not null, - screen_name varchar2(100) - constraint users_screen_name_un - unique, - priv_name integer default 0 not null, - priv_email integer default 5 not null, - email_verified_p char(1) default 't' - constraint users_email_verified_p_ck - check (email_verified_p in ('t', 'f')), - email_bouncing_p char(1) default 'f' not null - constraint users_email_bouncing_p_ck - check (email_bouncing_p in ('t','f')), - no_alerts_until date, - last_visit date, - second_to_last_visit date, - n_sessions integer default 1 not null, - -- local authentication information - password char(40), - salt char(40), - password_question varchar2(1000), - password_answer varchar2(1000), - -- table constraints - constraint users_authority_username_un - unique (authority_id, username) -); - - - - by - -Peter -Marklund - - - - - - EXT -AUTH #32: Service Contract Implementation Parameters - - - Execution Story - - When the administrator configures an authority to use a -specific service contract implementation, e.g. PAM, that -implementation can say which parameters it supports, e.g. Host, -Port, Root node, etc. - - The administrator will specify values for these parameters as -part of configuring the authority. - - These parameter values will be passed along to the service -contract implementation when its methods get called. - - - - Tradeoffs - - Flexibility, usability. - - - - External Design - - We're considering whether to implement a very simple solution -a' la current package parameters, or a general configuration -solution as outlined in the -Configurator -Spec -. - - - - Data Model - - Simple solution: A table with key/value pairs attached to the -auth_authorities table. - - - - Time Estimate - - Original estimate, simple solution: 8 hours - - Original estimate, complex solution: 50 hours - - Hours spent: - - Estimated hours remaining: - - Risk: - - - - - - - OACS-COL-1: -Automate install and self-test (5 hours) - - by - -Peter -Marklund - - - I need to make sure the install scripts work. I then need to: - - - Schedule nightly recreation - - - - Make sure the install script invokes -acs-automated-testing tests and checks results - - - - Make sure emails go out to appropriate people - - - - by - -Peter -Marklund - - - - - - EXT AUTH #x: Title -of feature - - - Current Design - - Describe how any functionality to be replaced works. - - - - Execution Story - - Beginning with a human being using a computer, describe how -the feature is triggered and what it does. As this story becomes -more detailed, move pieces to appropriate parts of the -document. - - - - Tradeoffs - - Which one or two of the following are emphasised in this -design? - - - - Performance: availability and efficiency - - - - Flexibility - - - - Interoperability - - - - Reliability and robustness - - - - Usability - - - - Maintainability - - - - Portability - - - - Reusability - - - - Testability - - - - - - External Design - - For a feature with a public API, write the stub for each -procedure, showing all parameters, a preliminary description of -instructions, and expected return. - - For a feature without a public API, describe how the feature -is invoked. - - Include admin-configurable parameters. - - - - Page Flow - - For features with UI, a map of all pages, showing which pages -can call others, which are includeable, etc. For each page, show -all UI elements on the page (text blocks, forms, form controls). -Include administration functionality. - - - - Internal Design - - Describe key algorithms, including pseudo-code. - - - - Data Model - - Describe data model changes. - - - - Error Handling - - What error codes or error conditions could result? How are -they handled? - - - - Upgrade - - Describe in pseudo-code how upgrade will be -implemented. - - - - Time Estimate - - Original estimate: - - Hours spent: - - Estimated hours remaining: - - Risk: - - - - - \ No newline at end of file