3 * FusionForge authentication management
5 * Copyright 2011, Roland Mas
7 * This file is part of FusionForge. FusionForge is free software;
8 * you can redistribute it and/or modify it under the terms of the
9 * GNU General Public License as published by the Free Software
10 * Foundation; either version 2 of the Licence, or (at your option)
13 * FusionForge is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 // See for details http://lists.fusionforge.org/pipermail/fusionforge-general/2011-February/001335.html
25 define('FORGE_AUTH_AUTHORITATIVE_ACCEPT', 1);
26 define('FORGE_AUTH_AUTHORITATIVE_REJECT', 2);
27 define('FORGE_AUTH_NOT_AUTHORITATIVE', 3);
30 * Pluggable Authentication plugins base class
32 * By default, the session cookie is used
35 abstract class ForgeAuthPlugin extends Plugin {
37 * ForgeAuthPlugin() - constructor
40 function ForgeAuthPlugin() {
42 // Common hooks that can be enabled per plugin:
43 // check_auth_session - is there a valid session?
44 // fetch_authenticated_user - what GFUser is logged in?
45 // display_auth_form - display a form to input credentials
46 // display_create_user_form - display a form to create a user from external auth
47 // sync_account_info - sync identity from external source (realname, email, etc.)
48 // get_extra_roles - add new roles not necessarily stored in the database
49 // restrict_roles - filter out unwanted roles
50 // close_auth_session - terminate an authentication session
52 $this->saved_user = NULL;
56 function CallHook ($hookname, &$params) {
58 case 'check_auth_session':
59 $this->checkAuthSession($params);
61 case 'fetch_authenticated_user':
62 $this->fetchAuthUser($params);
64 case 'display_auth_form':
65 // no default implementation, but see AuthBuiltinPlugin::displayAuthForm()
66 // $params can be passed with a 'return_to' attribute
67 // it should return an HTML dialog appened to passed $params['html_snippets']
68 // it may return a redirection URL appened to $params['transparent_redirect_urls']
69 $this->displayAuthForm($params);
71 case 'display_create_user_form':
72 // no default implementation
73 $this->displayCreateUserForm($params);
75 case 'sync_account_info':
76 // no default implementation
77 $this->syncAccountInfo($params);
79 case 'get_extra_roles':
80 $this->getExtraRoles($params);
82 case 'restrict_roles':
83 $this->restrictRoles($params);
85 case 'close_auth_session':
86 $this->closeAuthSession($params);
100 protected $saved_user;
103 * Is there a valid session?
105 * @param array $params
106 * @return FORGE_AUTH_AUTHORITATIVE_ACCEPT, FORGE_AUTH_AUTHORITATIVE_REJECT or FORGE_AUTH_NOT_AUTHORITATIVE
107 * TODO : document 'auth_token' param
109 function checkAuthSession(&$params) {
110 // check the session cookie/token to get a user_id
111 if (isset($params['auth_token']) && $params['auth_token'] != '') {
112 $user_id = $this->checkSessionToken($params['auth_token']);
114 $user_id = $this->checkSessionCookie();
117 $this->saved_user = user_get_object($user_id);
118 if ($this->isSufficient()) {
119 $params['results'][$this->name] = FORGE_AUTH_AUTHORITATIVE_ACCEPT;
121 $params['results'][$this->name] = FORGE_AUTH_NOT_AUTHORITATIVE;
124 $this->saved_user = NULL;
125 if ($this->isRequired()) {
126 $params['results'][$this->name] = FORGE_AUTH_AUTHORITATIVE_REJECT;
128 $params['results'][$this->name] = FORGE_AUTH_NOT_AUTHORITATIVE;
134 * What GFUser is logged in?
136 * This will generate a valid forge user (by default, it was generated and cached already in saved_user)
138 * @param array $params
139 * @return array $params['results'] containing user object
141 function fetchAuthUser(&$params) {
142 if ($this->saved_user && $this->isSufficient()) {
143 $params['results'] = $this->saved_user;
148 * Terminate an authentication session
149 * @param array $params
151 function closeAuthSession($params) {
152 if ($this->isSufficient() || $this->isRequired()) {
153 $this->unsetSessionCookie();
158 * Add new roles not necessarily stored in the database
159 * @param array $params
161 function getExtraRoles(&$params) {
162 // $params['new_roles'][] = RBACEngine::getInstance()->getRoleById(123);
166 * Filter out unwanted roles
167 * @param array $params
169 function restrictRoles(&$params) {
170 // $params['dropped_roles'][] = RBACEngine::getInstance()->getRoleById(123);
173 // Helper functions for individual plugins
174 // FIXME : where is $this->cookie_name set ?
175 protected $cookie_name;
178 * Returns the session cookie name for the auth plugin (by default forge_session_AUTHPLUGINNAME)
182 protected function getCookieName() {
183 if ($this->cookie_name) {
184 return $this->cookie_name;
186 return 'forge_session_'.$this->name;
189 protected function checkSessionToken($token) {
190 return session_check_session_token($token);
193 protected function checkSessionCookie() {
194 $token = getStringFromCookie($this->getCookieName());
195 return $this->checkSessionToken($token);
199 * Sets the session cookie according to the user in $this->saved_user
201 protected function setSessionCookie() {
202 if($this->saved_user) {
203 $cookie = session_build_session_token($this->saved_user->getID());
204 session_set_cookie($this->getCookieName(), $cookie, "", forge_get_config('session_expire'));
209 * Start a new session for a user
211 * @param string $username
214 function startSession($username) {
215 if ($this->isSufficient() || $this->isRequired()) {
217 $params['username'] = $username;
218 $params['event'] = 'login';
219 plugin_hook('sync_account_info', $params);
220 $user = user_get_object_by_name_or_email($username);
221 $this->saved_user = $user;
222 $this->setSessionCookie();
229 protected function unsetSessionCookie() {
230 session_set_cookie($this->getCookieName(), '');
234 * TODO: Enter description here ...
235 * @return Ambigous <Ambigous, NULL, boolean>
237 public function isRequired() {
238 return forge_get_config('required', $this->name);
242 * TODO: Enter description here ...
243 * @return Ambigous <Ambigous, NULL, boolean>
245 public function isSufficient() {
246 return forge_get_config('sufficient', $this->name);
250 * TODO: Enter description here ...
251 * @param unknown_type $event
254 public function syncDataOn($event) {
255 $configval = forge_get_config('sync_data_on', $this->name);
258 switch ($configval) {
260 $events = array('every-page','login','user-creation');
263 $events = array('login','user-creation');
265 case 'user-creation':
266 $events = array('user-creation');
273 return in_array($event, $events);
277 * TODO: Enter description here ...
279 protected function declareConfigVars() {
280 forge_define_config_item ('required', $this->name, 'no');
281 forge_set_config_item_bool ('required', $this->name) ;
283 forge_define_config_item ('sufficient', $this->name, 'no');
284 forge_set_config_item_bool ('sufficient', $this->name) ;
286 forge_define_config_item ('sync_data_on', $this->name, 'never');
292 // c-file-style: "bsd"