SPF - 0.1 - http://www.tomsick.net/projects/spf Robert Tomsick (robert@tomsick.net) ================================================= This document: + Description + License - License Q & A + Usage Instructions - Deployment - Notes, bugs, etc. + Contact Description =========== What is SPF? ------------ SPF is a simple PHP library providing authentication, authorization, and session management functionality. It is designed to be flexible, secure, and easy to incorporate into your site/application. SPF was inspired by Spring Security (although it is currently nowhere near as full-featured.) If you've used Spring Security before, SPF's design will probably seem very intuitive. License ======= SPF is provided under the terms of the Affero GPL v.3. For more details and for a copy of the license, please see the LICENSE file included along with this software. License Q & A ------------- Q: What does the license require me to do? A: If you use SPF as part of your project/site, you must make available a copy of the SPF source, including any modifications that you may have made to it. Q: Does this mean I have to post the source code to my entire site? A: No. You only need to make available a copy of the SPF source, along with any modifications that you've made to it. Q: What does "make available" mean? A: You must either offer a link to the SPF source code or make an offer to provide the source code upon request. You cannot simply mention SPF and link back to the project's home page. You must offer and supply the source code yourself. Q: Can I obfuscate the source code using some sort of "script encoder" or "source protection" software? A: No. This is not allowed under the terms of the AGPL. Q: Hmm... that doesn't really work for me. Is there another option? A: Yes. Just drop me an e-mail (see 'Contact'), and we can work out something more suitable for your needs. Usage Instructions ================== I. Deployment A. Installation B. Configuration 1. URLs 2. Session management 3. Password encoder 4. User data source 5. POST fields, callback, SPF_Gatekeeper configuration, etc. C. Usage 1. Login support 2. Roles/restrictions II. Notes, bugs, etc. I. Deployment ------------- A. Installation --------------- SPF doesn't require much in the way of installation. The basic steps are: 1) Copy the 'SPF' directory into a PHP-accessible location. 2) Copy the included 'SPF_config.php' file into a PHP-accessible location. 3) Edit the 'SPF_config.php' file. You will need to change the 'SPF_BASE_PATH' definition to reflect the path of the 'SPF' directory that you copied in step #1. 4) Perform any further changes to 'SPF_config.php' that you require (see section I.B for more information on configuring SPF.) 5) Copy 'SPF_handler.php' to a suitable location. If necessary, edit to reflect the location of 'SPF_config.php'. 6) Configure mod_rewrite (or equivalent) to redirect the URLs specified for 'login_post_url' and 'logout_url' to the handler script from step #5. A sample mod_rewrite configuration is provided below: RewriteEngine on # login_post_url RewriteRule spf_security_check SPF_handler.php [L] # logout_url RewriteRule spf_logout SPF_handler.php [L] That's it! SPF is now installed. Read on for configuration and usage instructions. B. Configuration --------------- 1. URLs ------- SPF is flexible when it comes to the URLs it uses for the various stages of the login/logout processes. The following configuration variables control the URLs that SPF uses: login_post_url the URL to which usernames/passwords will be submitted by your login form login_failure_url the URL to which users will be redirected after an unsuccessful login attempt login_success_url the URL to which users will be redirected after a successful login logout_url the URL used to handle user logouts -- a request to this URL will result in the user's session being terminated and the user being logged out logout_redirect_url the URL to which the user will be redirected after logging out 2. Session management --------------------- SPF's default session manager provides a simple wrapper around PHP's built-in session functionality. It provides some measure of protection against session hijacking and replay attacks and should be sufficient for most small sites. SPF_SessionManager only requires one configuration parameter: 'domain'. This parameter should contain the domain for which you want the session cookie to be valid. This is almost always the domain name of the site for which you are using SPF. 3. Password encoder ------------------- SPF comes with built-in support for a strong password encoding system. This implementation provides support for multi-round hashing as well as for the use of per-user salts. SPF currently only comes with one implementation of SPF_PasswordEncoder (SPF_MultiRoundHashPasswordEncoder), but it is configurable enough that it should suffice for almost all applications. SPF_MultiRoundHashPasswordEncoder does not need to be explicitly configured, although an instance of it does need to be supplied to the gatekeeper in the configuration file. You may specify the hash algorithm and number of rounds to use via the constructor, but it is not necessary to do so. If no algorithm and/or number of rounds are specified, then 10000 rounds of the RIPEMD-160 algorithm will be used by default (as of v. 0.1). Encoding passwords for your application (such as when creating new users) may be done by instantiating the encoder and calling the encode() function with the user's password and a salt. If no salt is provided, none will be used. (Note: use of a randomly-generated, per-user salt is *strongly* advised.) For more information, consult SPF/SPF_MultiRoundHashPasswordEncoder.php 4. User data source ------------------- SPF provides a pluggable architecture for loading user data. The SPF_UserDataSource interface specifies the functions which a user data source must implement. SPF currently ships with one such implementation (SPF_PDOUserDataSource) which provides support for loading user data from any database supported by PDO (MySQL, SQLite, etc.) SPF_PDOUserDataSource --------------------- SPF_PDOUserDataSource does not require the use of a specific database structure. It provides a number of in-built queries designed to match a typical user table, support for the use of different column names in the pre-defined queries, and support for the use of custom SQL queries for the retrieval of user data. The following options must be configured: db_string - the PDO connection string used to connect to your database db_user - the username to use when connecting to your database db_pass - the password to use when connecting to your database The following options may be configured if you wish to use the built-in queries against a database with different table/column names: user_table - the name of the table containing user information Default value: 'spf_users' col_username - the column containing usernames Default value: 'username' col_user_id - the column containing user IDs Default value: 'user_id' col_password - the column containing user password hashes Default value: 'password' col_password_salt - the column containing per-user password salts Default value: 'passwordSalt' col_roles - the column containing user roles Note: roles are assumed to be stored as a string in comma-delimited format. Default value: 'roles' The following options may be configured if you wish to override the queries used to retrieve user information from the database: query_load_user_by_username - the query used to load a user by their username Default value: see SQL_LOAD_USER_BY_USERNAME query_load_user_by_user_id - the query used to load a user by their user ID Default value: see SQL_LOAD_USER_BY_USER_ID query_load_all_users - the query used to load all users Default value: see SQL_LOAD_ALL_USERS NOTE: if you intend to use custom queries, it is recommended that you take a look at the implementation of SPF_PDOUserDataSource so as to see how the queries are used. The explanation above does not cover all the requirements for use of custom queries. 5. POST fields, callback, SPF_Gatekeeper configuration etc. ------------------------------ SPF supports a couple of other configurable options that make integration easier. These options are supplied to SPF_Gatekeeper in the configuration: login_username_field - the POST variable in which usernames will be supplied to the login URL Default value: 'spf_username' login_password_field - the POST variable in which passwords will be supplied to the login URL Default value: 'spf_password' authorization_failure_callback - the name of a function to be called upon failed authorization attempts. This function will be called in the event that a user attempts to access a resource restricted to a role that he does not have. When called, the function will be supplied with an array containing the role required and the SPF_User object of the current user. If the current user does not have an authentication token set (i.e. if he is not logged in / anonymous), the second element of the supplied array will be NULL. Please note: this will *not* be called for failed logins -- just for authorization failures. bad_auth_is_fatal - whether or not failed authorizations should be considered fatal. If TRUE, calls to restrict() will terminate execution if the current user does not have the specified role. If FALSE, calls to restrict() will return either TRUE or FALSE depending on whether or not the current user has the specified role. authorization_failure_callback will function the same way regardless of this setting. For a full list of the configurable aspects of the gatekeeper, please see the source of SPF_Gatekeeper (located in SPF/Gatekeeper.php) C. Usage -------- 1. Login support ---------------- Integrating support for logins/logouts is quite simple. Assuming that you have configured SPF according to the instructions in I.A, you need only do the following: Login ----- Create or update your login form so that it submits a username and password to the URL specified by 'login_post_url'. Form submission should be done via POST. If you have not explicitly configured the variable names used for the username and password (see sec. I.B.5), then your form should use 'spf_username' for the username and 'spf_password' for the password. Logout ------ To log out, all a user needs to do is visit the URL specified in the configuration variable 'logout_url'. Therefore, all you need to do to log out a user is have their browser access that URL. How you do this is up to you; the simplest way is just to point your "logout now" link at said URL. If you did not explicitly set a custom logout URL (see sec. I.B.1), then the default URL of '/spf_logout' will used. That's pretty much it. 2. Roles/restrictions --------------------- Login/logout support doesn't mean much unless SPF is protecting something. In order to protect the various resources of your application/site you will need to deploy role-based restrictions throughout your site. To restrict a page or a function to a specific role, simple call the restrict() function of SPF_Gatekeeper. This function expects an argument containing a string with the role name -- if none is provided, the role name 'ANONYMOUS' is used. It is entirely up you to provide roles -- SPF does not have any predefined roles, so this functionality is entirely dependent on your role setup. The simplest way (which will suffice for most small sites) is to simply create a single role for all members/registered users/etc. and restrict your members-only functionality to said role. SPF has deliberately been left rather open-ended in this regard; there is no one-size-fits-all setup for this sort of thing. restrict() may be called anywhere that you have access to an SPF_Gatekeeper instance. It doesn't have to be called at the start of a page -- you can include it anywhere. This means that you can restrict certain functions to certain roles, etc. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! IMPORTANT: !!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !! If restrict() is called and the current user is found not to have the !! specified role, the default behavior is to terminate the script (after !! the callback function is called). !! !! To avoid having authorization failures result in script termination, !! you will need to set the configuration variable 'bad_auth_is_fatal' to !! FALSE (the default is TRUE.) If set to FALSE, the restrict() function !! will return FALSE in the event that the user does not have the !! specified role, and TRUE otherwise (i.e. if they are authorized.) !! Correspondingly, if you set 'bad_auth_is_fatal' to FALSE, you must !! then check the return value of restrict(), or else SPF's restrictions !! will effectively cease to exist. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! II. Notes, bugs, etc. --------------- SPF is designed to be easy to extend. Interfaces are defined for user data sources and password encoding, and the session manager was written so as to be easy to subclass. Earlier versions of SPF have been used in production environments (this release is just a cleaned-up, enhanced version of the authentication and authorization library written for M2Feed). This is, however, the very first release of SPF as a completely stand-alone library and as a result there may be bugs. If you find any bugs in SPF, please let me know as soon as possible (see 'Contact' below for my contact information.) One quick note: if you get warnings informing you that PHP "Cannot send session cache limiter - headers already sent", you're probably including SPF_config.php after you've already sent some output. The only real requirement regarding include order, etc. is that SPF_config.php must be included before you send anything out to the browser in order for session support to work. (For the curious: this happens because the session manager will try to start a session as soon as it's instantiated. Since it's instantiated in the config file, this means that SPF configuration must be done prior to any output being sent out to the browser.) Sample SQL Schema ----------------- The following is an example MySQL schema for a table that can be used with SPF_PDOUserDataSource's in-built columns/queries: CREATE TABLE IF NOT EXISTS `spf_users` ( `username` varchar(80) NOT NULL, `user_id` int(11) NOT NULL auto_increment, `password` varchar(80) NOT NULL, `passwordSalt` varchar(80) NOT NULL, `roles` text NOT NULL, PRIMARY KEY (`user_id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=2 ; Contact ======= If you'd like to contact me (the author of SPF) you can e-mail me at: robert@tomsick.net Alternately, you can contact me via XMPP, AIM, or other methods using the information on the following page: http://www.tomsick.net/contact Please report any bugs that you may find. Patches are welcome, and any feedback is greatly appreciated.