I need to create a custom SSO plugin. The way it should work is:
- User authenticates on 3rd party application
- 3rd party application calls a Joomla URL via POST request
- The URL that has been hit deals with authentication on Joomla's end
- User is logged in both on Joomla and on 3rd party application
I know how to create a custom plugin for authentication as I've done it in the past, but I can't find a way to expose a plugin URL for point 2. Is there a way to expose a plugin URL, or is there any other way to achieve the above? Users will register and login on the 3rd party application, but I still need them authenticated on the Joomla website. Thank you.
UPDATE
I have tried to implement the procedure outlined below, including the plugin from a component, but it's not working.
/components/com_testauth/controllers/sso.php
class TestAuthControllerSso extends JControllerLegacy
{
public function auth() {
JPluginHelper::importPlugin('user');
JPluginHelper::importPlugin('authentication');
$dispatcher = JEventDispatcher::getInstance();
$options = '';
$response = new \stdClass();
$credentials = array();
$credentials["username"] = "test";
$credentials["password"] = "tset";
$results = $dispatcher->trigger('onUserAuthenticate', array($credentials,
$options, &$response));
return $results;
}
}
/plugins/authentication/test/test.php (This has been copied from Joomla documentation to test the functionality)
class PlgAuthenticationTest extends JPlugin
{
function onUserAuthenticate( $credentials, $options, &$response )
{
/*
* Here you would do whatever you need for an authentication routine with the credentials
*
* In this example the mixed variable $return would be set to false
* if the authentication routine fails or an integer userid of the authenticated
* user if the routine passes
*/
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select('id')
->from('#__users')
->where('username=' . $db->quote($credentials['username']));
$db->setQuery($query);
$result = $db->loadResult();
if (!$result) {
$response->status = STATUS_FAILURE;
$response->error_message = 'User does not exist';
}
/**
* To authenticate, the username must exist in the database, and the password should be equal
* to the reverse of the username (so user joeblow would have password wolbeoj)
*/
if($result && ($credentials['username'] == strrev( $credentials['password'] )))
{
$email = JUser::getInstance($result); // Bring this in line with the rest of the system
$response->email = $email->email;
$response->status = JAuthentication::STATUS_SUCCESS;
return true;
}
else
{
$response->status = JAuthentication::STATUS_FAILURE;
$response->error_message = 'Invalid username and password';
}
}
}
The problem is that I can log in ok if I log in through the log in form, but I can't log in if I call the component controller from the URL. The credentials of the user are hard-coded to avoid mistakes, so that the authentication should always be correct.
The process I followed is:
- Created a component that includes the authentication plugin. a. Please note that I'm including the whole "authentication" plugin, including the single plugin doesn't seem to work.
- Created an authentication plugin
- Visited the controller URL - index.php?option=com_testauth&task=sso.auth
UPDATE 2
I have come up with another solution, which unfortunately it's not working at 100%, but it may help people in the future.
What I did is:
- Created an Ajax plugin, and installed it as an Ajax plugin in Joomla to expose the URL, code as follows:
`
function onAjaxSSO()
{
$app = JFactory::getApplication();
$input = $app->input;
$app->setHeader('X-Robots-Tag', 'noindex, nofollow');
$task = $input->get("task", "", "cmd");
$app->logout(JFactory::getUser()->id, array());
//Do all the security checks to see if the call is legit or not and if it has all the right details.
[...]
//Pass the details to the authentication plugin
$loginResponse = $app->login(array('username' => $username, 'email' => $email, 'password' => $password, 'name' => $forename.' '.$surname), array('silent' => true));
//Check what is the response from the authentication plugin and display the message on the API response
if($loginResponse === true) {
$app->setHeader('status', 200, true);
$result = "";
echo new JResponseJson($result, 'Success - User is authenticated', false);
return $app->close();
}
else {
$app->setHeader('status', 401, true);
$result = '';
echo new JResponseJson($result, 'Unauthorized - User is not authenticated', true);
return $app->close();
}
}
`
- Created an authentication plugin, this deals with all the authentication stuff. Code as follows, parts are missing for brevity:
`
function onUserAuthenticate( $credentials, $options, &$response )
{
$app = JFactory::getApplication();
//No log in for admins
if ($app->isClient('administrator')) {
$response->status = JAuthentication::STATUS_FAILURE;
return false;
}
//We check Joomla database to see if the details are the same
[...]
//Authenticate the user if everything looks legit
$user = JUser::getInstance($joomlaId);
$response->email = $user->email;
$response->fullname = $user->name;
$response->username = $user->username;
$response->language = $user->getParam('language');
$response->status = JAuthentication::STATUS_SUCCESS;
$response->error_message = '';
}
`
When I call the API exposed with the Ajax plugin, I get a "true" response from the plugin, the authentication goes fine (I can see the user being updated/inserted on the database), and I can also see, from the back-end, the user in the list of "Active users", but nothing changes on the front-end. The user is not properly logged-in, the joomla_user_state cookie has not been created and everything seems like the user has never logged in. If I try to print
echo JFactory::getUser()->id
I get 0.
task
and some parameters to call the authentication plugin. The params were non-descript but essentially used to check in the authentication plugin if the user was currently logged in on the WordPress site. All the auth plugin has to do is return true/false. Might be worth thinking about - at the time (circa 5 years ago) - there was no other method I found which would do this.onUserAuthenticate
event of a custom authentication plugin? Is this achieved by using JPluginHelper as below?JPluginHelper::importPlugin('mycustomauth'); $dispatcher = JEventDispatcher::getInstance(); $dispatcher->trigger('onUserAuthenticate', $data);
mycustomauth
plugin to handle$data
and return true/false to authenticate the user.