mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
mlanthaler: Initial import of the OpenID authenticator and form class.
OpenIDAuthenticator_Controller not yet implemented. (merged from branches/gsoc) git-svn-id: svn://svn.silverstripe.com/silverstripe/open/modules/sapphire/trunk@41769 467b73ca-7a2a-4603-9d3b-597d59a354a9
This commit is contained in:
parent
aadac616c0
commit
7b3f754add
@ -3,6 +3,7 @@
|
||||
* Log-in form for the "member" authentication method
|
||||
*/
|
||||
class MemberLoginForm extends Form {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@ -97,7 +98,7 @@ class MemberLoginForm extends Form {
|
||||
/**
|
||||
* Log out
|
||||
*
|
||||
* @todo Figure out for what this method is used!
|
||||
* @todo Figure out for what this method is used! Is it really used at all?
|
||||
*/
|
||||
public function logout(){
|
||||
$s = new Security();
|
||||
@ -105,16 +106,19 @@ class MemberLoginForm extends Form {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check the membership
|
||||
*
|
||||
* If one of them or both don't match, set the fields which are unmatched with red star *
|
||||
*/
|
||||
/**
|
||||
* Try to authenticate the user
|
||||
*
|
||||
* @param array Submitted data
|
||||
* @return Member Returns the member object on successful authentication
|
||||
* or NULL on failure.
|
||||
*/
|
||||
public function performLogin($data){
|
||||
if($member = MemberAuthenticator::authenticate($data)) {
|
||||
$firstname = Convert::raw2xml($member->FirstName);
|
||||
$this->sessionMessage("Welcome Back, {$firstname}", "good");
|
||||
$member->LogIn();
|
||||
|
||||
if(isset($data['Remember'])) {
|
||||
// Deliberately obscure...
|
||||
Cookie::set('alc_enc',base64_encode("$data[Email]:$data[Password]"));
|
||||
|
219
security/OpenIDAuthenticator.php
Normal file
219
security/OpenIDAuthenticator.php
Normal file
@ -0,0 +1,219 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Require the OpenID consumer code.
|
||||
*/
|
||||
require_once "Auth/OpenID/Consumer.php";
|
||||
|
||||
/**
|
||||
* Require the "file store" module, which we'll need to store
|
||||
* OpenID information.
|
||||
*/
|
||||
require_once "Auth/OpenID/FileStore.php";
|
||||
|
||||
/**
|
||||
* Require the Simple Registration extension API.
|
||||
*/
|
||||
require_once "Auth/OpenID/SReg.php";
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* OpenID authenticator
|
||||
*
|
||||
* @author Markus Lanthaler <markus@silverstripe.com>
|
||||
*/
|
||||
class OpenIDAuthenticator extends Authenticator {
|
||||
|
||||
/**
|
||||
* Method to authenticate an user
|
||||
*
|
||||
* @param array $RAW_data Raw data to authenticate the user
|
||||
* @return bool|Member Returns FALSE if authentication fails, otherwise
|
||||
* the member object
|
||||
*/
|
||||
public function authenticate(array $RAW_data) {
|
||||
$openid = $RAW_data['OpenIDURL'];
|
||||
|
||||
$trust_root = Director::absoluteBaseURL();
|
||||
$return_to_url = $trust_root . 'OpenIDAuthenticator_Controller';
|
||||
|
||||
/**
|
||||
* @todo Change the store to use the database!
|
||||
*/
|
||||
// FIXXXME
|
||||
$store_path = TEMP_FOLDER;
|
||||
|
||||
if(!file_exists($store_path) && !mkdir($store_path)) {
|
||||
print "Could not create the FileStore directory '$store_path'. ".
|
||||
" Please check the effective permissions.";
|
||||
exit(0);
|
||||
}
|
||||
$store = new Auth_OpenID_FileStore($store_path);
|
||||
// END FIXXXME
|
||||
$consumer = new Auth_OpenID_Consumer($store, new SessionWrapper());
|
||||
|
||||
|
||||
// Begin the OpenID authentication process.
|
||||
$auth_request = $consumer->begin($openid);
|
||||
|
||||
// No auth request means we can't begin OpenID.
|
||||
if(!$auth_request) {
|
||||
displayError("Authentication error; not a valid OpenID.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @todo Check if the POST request should be send directly (without rendering a form)
|
||||
*/
|
||||
// For OpenID 1, send a redirect. For OpenID 2, use a Javascript
|
||||
// form to send a POST request to the server.
|
||||
if($auth_request->shouldSendRedirect()) {
|
||||
$redirect_url = $auth_request->redirectURL($trust_root, $return_to_url);
|
||||
|
||||
// If the redirect URL can't be built, display an error
|
||||
// message.
|
||||
if(Auth_OpenID::isFailure($redirect_url)) {
|
||||
displayError("Could not redirect to server: " . $redirect_url->message);
|
||||
} else {
|
||||
Director::redirect($redirect_url);
|
||||
// header("Location: ".$redirect_url);
|
||||
|
||||
}
|
||||
} else {
|
||||
// Generate form markup and render it.
|
||||
$form_id = 'openid_message';
|
||||
$form_html = $auth_request->formMarkup($trust_root, $return_to_url,
|
||||
false, array('id' => $form_id));
|
||||
|
||||
// Display an error if the form markup couldn't be generated;
|
||||
// otherwise, render the HTML.
|
||||
if(Auth_OpenID::isFailure($form_html)) {
|
||||
displayError("Could not redirect to server: " . $form_html->message);
|
||||
} else {
|
||||
$page_contents = array(
|
||||
"<html><head><title>",
|
||||
"OpenID transaction in progress",
|
||||
"</title></head>",
|
||||
"<body onload='document.getElementById(\"".$form_id."\").submit()'>",
|
||||
$form_html,
|
||||
"</body></html>");
|
||||
|
||||
print implode("\n", $page_contents);
|
||||
}
|
||||
}
|
||||
exit();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method that creates the login form for this authentication method
|
||||
*
|
||||
* @return Form Returns the login form to use with this authentication
|
||||
* method
|
||||
*/
|
||||
public function getLoginForm() {
|
||||
return Object::create("OpenIDLoginForm", $this, "LoginForm");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* OpenIDAuthenticator Controller
|
||||
*
|
||||
* This class handles the response of the OpenID server to authenticate
|
||||
* the user
|
||||
*
|
||||
* @author Markus Lanthaler <markus@silverstripe.com>
|
||||
*/
|
||||
class OpenIDAuthenticator_Controller extends Controller {
|
||||
|
||||
/**
|
||||
* Run the controller
|
||||
*/
|
||||
function run($requestParams) {
|
||||
parent::init();
|
||||
|
||||
if(isset($_GET['debug_profile'])) Profiler::mark("OpenIDAuthenticator_Controller");
|
||||
|
||||
die("Not implemented yet!");
|
||||
|
||||
if(isset($_GET['debug_profile'])) Profiler::unmark("OpenIDAuthenticator_Controller");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to set a session message for the OpenID login form
|
||||
*
|
||||
* @param string $message Message to store
|
||||
* @param string $type Message type (e.g. "good" or "bad")
|
||||
*/
|
||||
function sessionMessage($message, $type) {
|
||||
Session::set("FormInfo.OpenIDLoginForm_LoginForm.formError.message", $message);
|
||||
Session::set("'FormInfo.OpenIDLoginForm_LoginForm.formError.type", $type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Session wrapper class for the OpenID library
|
||||
*
|
||||
* This class is a wrapper for the {@link Session} which implements the
|
||||
* interface of the {@link Auth_Yadis_PHPSession} class.
|
||||
*
|
||||
* @author Markus Lanthaler <markus@silverstripe.com>
|
||||
*/
|
||||
class SessionWrapper {
|
||||
|
||||
/**
|
||||
* Set a session key/value pair.
|
||||
*
|
||||
* @param string $name The name of the session key to add.
|
||||
* @param string $value The value to add to the session.
|
||||
*/
|
||||
public function set($name, $value) {
|
||||
Session::set($name, $value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a key's value from the session.
|
||||
*
|
||||
* @param string $name The name of the key to retrieve.
|
||||
* @param string $default The optional value to return if the key
|
||||
* is not found in the session.
|
||||
* @return string $result The key's value in the session or
|
||||
* $default if it isn't found.
|
||||
*/
|
||||
public function get($name, $default=null) {
|
||||
$value = Session::get($name);
|
||||
if(is_null($value))
|
||||
$value = $default;
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove a key/value pair from the session.
|
||||
*
|
||||
* @param string $name The name of the key to remove.
|
||||
*/
|
||||
public function del($name) {
|
||||
Session::clear($name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the contents of the session in array form.
|
||||
*/
|
||||
public function contents() {
|
||||
return Session::getAll();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
140
security/OpenIDLoginForm.php
Normal file
140
security/OpenIDLoginForm.php
Normal file
@ -0,0 +1,140 @@
|
||||
<?php
|
||||
|
||||
|
||||
/**
|
||||
* OpenID log-in form
|
||||
*
|
||||
* @author Markus Lanthaler <markus@silverstripe.com>
|
||||
*/
|
||||
class OpenIDLoginForm extends Form {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param $controller
|
||||
* @param $name
|
||||
* @param $fields
|
||||
* @param $actions
|
||||
* @param $checkCurrentUser
|
||||
*/
|
||||
function __construct($controller, $name, $fields = null, $actions = null,
|
||||
$checkCurrentUser = true) {
|
||||
$customCSS = project() . '/css/openid_login.css';
|
||||
if(Director::fileExists($customCSS)) {
|
||||
Requirements::css($customCSS);
|
||||
}
|
||||
|
||||
if(isset($_REQUEST['BackURL'])) {
|
||||
$backURL = $_REQUEST['BackURL'];
|
||||
} else {
|
||||
$backURL = Session::get('BackURL');
|
||||
//Session::clear("BackURL"); don't clear the back URL here! Should be used until the right password is entered!
|
||||
}
|
||||
|
||||
if($checkCurrentUser && Member::currentUserID()) {
|
||||
$fields = new FieldSet();
|
||||
$actions = new FieldSet(new FormAction("logout", "Log in as someone else"));
|
||||
} else {
|
||||
if(!$fields) {
|
||||
$fields = new FieldSet(
|
||||
new HiddenField("AuthenticationMethod", null, "OpenID"),
|
||||
new TextField("OpenIDURL", "OpenID URL",
|
||||
Session::get('SessionForms.OpenIDLoginForm.OpenIDURL')),
|
||||
new CheckboxField("Remember", "Remember me next time?", true)
|
||||
);
|
||||
}
|
||||
if(!$actions) {
|
||||
$actions = new FieldSet(
|
||||
new FormAction("dologin", "Log in")
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($backURL)) {
|
||||
$fields->push(new HiddenField('BackURL', 'BackURL', $backURL));
|
||||
}
|
||||
|
||||
parent::__construct($controller, $name, $fields, $actions);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get message from session
|
||||
*/
|
||||
protected function getMessageFromSession() {
|
||||
parent::getMessageFromSession();
|
||||
if(($member = Member::currentUser()) &&
|
||||
!Session::get('OpenIDLoginForm.force_message')) {
|
||||
$this->message = "You're logged in as $member->FirstName.";
|
||||
}
|
||||
Session::set('OpenIDLoginForm.force_message', false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Login form handler method
|
||||
*
|
||||
* This method is called when the user clicks on "Log in"
|
||||
*
|
||||
* @param array $data Submitted data
|
||||
*/
|
||||
public function dologin($data) {
|
||||
if($this->performLogin($data)){
|
||||
|
||||
if($backURL = $_REQUEST['BackURL']) {
|
||||
Session::clear("BackURL");
|
||||
Session::clear('SessionForms.OpenIDLoginForm.OpenIDURL');
|
||||
Director::redirect($backURL);
|
||||
} else
|
||||
Director::redirectBack();
|
||||
|
||||
} else {
|
||||
Session::set('SessionForms.OpenIDLoginForm.OpenIDURL', $data['OpenIDURL']);
|
||||
if($badLoginURL = Session::get("BadLoginURL")){
|
||||
Director::redirect($badLoginURL);
|
||||
} else {
|
||||
Director::redirectBack();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log out
|
||||
*
|
||||
* @todo Figure out for what this method is used! Is it really used at all?
|
||||
*/
|
||||
public function logout() {
|
||||
$s = new Security();
|
||||
return $s->logout();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try to authenticate the user
|
||||
*
|
||||
* @param array Submitted data
|
||||
* @return Member Returns the member object on successful authentication
|
||||
* or NULL on failure.
|
||||
*/
|
||||
public function performLogin(array $data) {
|
||||
if($member = OpenIDAuthenticator::authenticate($data)) {
|
||||
$firstname = Convert::raw2xml($member->FirstName);
|
||||
$this->sessionMessage("Welcome Back, {$firstname}", "good");
|
||||
$member->LogIn();
|
||||
|
||||
if(isset($data['Remember'])) {
|
||||
// Deliberately obscure...
|
||||
Cookie::set('alc_enc',base64_encode("$data[OpenIDURL]"));
|
||||
}
|
||||
return $member;
|
||||
|
||||
} else {
|
||||
$this->sessionMessage("Login failed. Please try again.", "bad");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -29,7 +29,7 @@ class Security extends Controller {
|
||||
* If you don't provide a messageSet, a default will be used.
|
||||
*/
|
||||
static function permissionFailure($page = null, $messageSet = null) {
|
||||
$loginForm = singleton('Security')->LoginForm();
|
||||
// $loginForm = singleton('Security')->LoginForm();
|
||||
|
||||
//user_error('debug', E_USER_ERROR);
|
||||
// Prepare the messageSet provided
|
||||
@ -60,7 +60,9 @@ class Security extends Controller {
|
||||
$message = $messageSet['default'];
|
||||
}
|
||||
|
||||
$loginForm->sessionMessage($message, 'warning');
|
||||
/* $loginForm->sessionMessage($message, 'warning');
|
||||
Session::set("SecurityMessage.Error.message", $message);
|
||||
Session::set("SecurityMessage.Error.type", $type);*/
|
||||
|
||||
// $_SESSION['LoginForm']['message'] = $message;
|
||||
Session::set("BackURL", $_SERVER['REQUEST_URI']);
|
||||
@ -73,15 +75,59 @@ class Security extends Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the login form to process according to the submitted data
|
||||
*/
|
||||
function LoginForm() {
|
||||
return MemberAuthenticator::GetLoginForm();
|
||||
if(is_array($_REQUEST) && isset($_REQUEST['AuthenticationMethod']))
|
||||
{
|
||||
switch($_REQUEST['AuthenticationMethod'])
|
||||
{
|
||||
case 'Member':
|
||||
return MemberAuthenticator::GetLoginForm();
|
||||
break;
|
||||
case 'OpenID':
|
||||
return OpenIDAuthenticator::GetLoginForm();
|
||||
break;
|
||||
}
|
||||
}
|
||||
user_error('Invalid authentication method', E_USER_ERROR);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the login forms for all available authentication methods
|
||||
*
|
||||
* @todo Check how to activate/deactivate authentication methods
|
||||
*/
|
||||
function GetLoginForms()
|
||||
{
|
||||
$forms = array();
|
||||
array_push($forms, MemberAuthenticator::GetLoginForm());
|
||||
array_push($forms, OpenIDAuthenticator::GetLoginForm());
|
||||
|
||||
return $forms;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a link to a security action
|
||||
*
|
||||
* @param string $action Name of the action
|
||||
*/
|
||||
function Link($action = null) {
|
||||
return "Security/$action";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Log the currently logged in user out
|
||||
*
|
||||
* @param bool $redirect Redirect the user back to where they came.
|
||||
* - If it's false, the code calling logout() is responsible for sending the user where-ever they should go.
|
||||
* - If it's false, the code calling logout() is
|
||||
* responsible for sending the user where-ever
|
||||
* they should go.
|
||||
*/
|
||||
function logout($redirect = true) {
|
||||
Cookie::set('alc_enc',null);
|
||||
@ -90,6 +136,10 @@ class Security extends Controller {
|
||||
if($redirect) Director::redirectBack();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function login() {
|
||||
Requirements::javascript("jsparty/behaviour.js");
|
||||
Requirements::javascript("jsparty/loader.js");
|
||||
@ -109,14 +159,23 @@ class Security extends Controller {
|
||||
return $controller->renderWith(array("Security_login", "Page"));
|
||||
|
||||
} else {
|
||||
$forms = $this->GetLoginForms();
|
||||
$content = '';
|
||||
foreach($forms as $form)
|
||||
$content .= $form->forTemplate();
|
||||
|
||||
$customisedController = $controller->customise(array(
|
||||
"Content" => $this->LoginForm()->forTemplate()
|
||||
"Content" => $content
|
||||
));
|
||||
|
||||
return $customisedController->renderWith("Page");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function lostpassword() {
|
||||
Requirements::javascript("jsparty/prototype.js");
|
||||
Requirements::javascript("jsparty/behaviour.js");
|
||||
@ -138,6 +197,10 @@ class Security extends Controller {
|
||||
return $customisedController->renderWith("Page");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function passwordsent() {
|
||||
Requirements::javascript("jsparty/behaviour.js");
|
||||
Requirements::javascript("jsparty/loader.js");
|
||||
@ -161,6 +224,9 @@ class Security extends Controller {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function LostPasswordForm() {
|
||||
return new MemberLoginForm($this, "LostPasswordForm", new FieldSet(
|
||||
new EmailField("Email", "Email address")
|
||||
@ -188,6 +254,7 @@ class Security extends Controller {
|
||||
return $member;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a member with administrator privileges
|
||||
*/
|
||||
@ -223,6 +290,7 @@ class Security extends Controller {
|
||||
return $member;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This will set a static default-admin (e.g. "td") which is not existing as
|
||||
* a database-record. By this workaround we can test pages in dev-mode with
|
||||
@ -240,6 +308,7 @@ class Security extends Controller {
|
||||
self::$password = $password;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set strict path checking. This prevents sharing of the session
|
||||
* across several sites in the domain.
|
||||
@ -250,8 +319,13 @@ class Security extends Controller {
|
||||
self::$strictPathChecking = $strictPathChecking;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
static function getStrictPathChecking() {
|
||||
return self::$strictPathChecking;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
?>
|
Loading…
Reference in New Issue
Block a user