Bogdan recently asked in my comments:

I can't seem to find a call like josso_authenticate($name, $pass), returning an array to be appended to user's SESSION. I was expecting such a method, because SOAP is already used everywhere, so it shouldn't be too hard implementing this. Has anyone had success implementing this kind of "transparent" login?

JOSSO simply doesn't make it easy to log people in with a single call. Instead you need to make an interface to the API to do so. I just so happen to have an example of such a wrapper function.

Logging In A User

To do everything and make it easy for future reuse I built two classes. The first is a Login Class and the second a Josso Class (below). My Login Class is pretty sparse, but it includes a wrapper to handle all the tasks required to login a user through Josso and get back the Josso details for that user.

The full code of each class is down at the bottom of the post, just expand the code block, but here is the function that is really what you are looking for Login->authorize()

Login->authorize()

[php]public function authorize($username, $password){

# make sure we have a valid username if(empty($username)){ # return invalid username throw new LoginException('Invalid username'); } else { $this->username = $username; }

# make sure we have a valid password if(empty($password)){ # return invalid username throw new LoginException('Invalid password'); }

# check that user exists if( ! $this->josso->userExists($this->username)){ throw new LoginException('Invalid username'); }

# check Josso with username and password $this->assertion = $this->josso->assertIdentityWithSimpleAuthentication($username, $password); if($this->josso->error){ throw new LoginException('Invalid username/password combination'); }

# resolve Authentication Assertion $this->token = $this->josso->resolveAuthenticationAssertion($this->assertion); if($this->josso->error){ throw new LoginException('Interal Error [Login]: '. LINE); }

$this->session = $this->josso->getSession($this->token); if($this->josso->error){ throw new LoginException('Interal Error [Login]: '. LINE); }

$this->user = $this->josso->findUserInSession($this->token); if($this->josso->error){ throw new LoginException('Interal Error [Login]: '. LINE); }

$this->cleanUpUser();

$this->roles = $this->josso->findRolesByUsername($this->username); if($this->josso->error){ throw new LoginException('Interal Error [Login]: '. LINE); }

$this->cleanUpRoles();

$this->user->sosPermissions =& $this->roles; }[/php]

What That Actually Did

As you can see you simply pass the $username and $password to the function and it runs through a ton of work for you.

First it validates the input, make sure you aren't working for no reason.

Next it makes sure the userExists(), this will save you heartache later when JOSSO pretends a user exists, but really doesn't.

Then I asserIdentityWithSimpleAuthentication() which literally means I pass those to JOSSO and wait for an answer. The answer returned is an assertion_id, which really doesn't mean anything.

You then take the assertionid returned and call resolveAuthenticationAssertion(), this will return your sessionid if the login was valid.

With the sessionid you call getSession(). This returns all the details of the session that JOSSO now has open. This varies depending on who setup your JOSSO implementation but you should have an identifying is (userid) if nothing else.

I go on to make sure that JOSSO hasn't forgotten anything by calling findUserInSession(), which literally just tells me who I am supposed to be working with.

The cleanUpUser() you could probably ignore, but our system returns an object with dots ( . ) in the name and I can't stand that, so I change them to underscores ( _ ).

Finally I call back to my JOSSO install to get any roles the user has, again this will vary if your JOSSO doesn't handle roles.

Login Class

[php collapse="true"]

class Login {

public $token; public $username; public $session; public $roles; public $user; public $request; private $assertion; # this will hold the instance of Josso Controller we need private $josso;

function Login($request = null){

$this->josso = new Josso; if(!empty($request)){ $this->request = $request; } }

#validate an existing token public function validateToken($usertoken){ $session = $this->josso->accessSession($usertoken);

/* * For whatever reason Josso returns nothing if the session is valid * and the operation has been completed. */ if( empty($session)){ return true; }

if($this->josso->error){ throw new LoginException('Internal Error [Login]: '. LINE); } return false; }

# authorize a user with password public function authorize($username, $password){

# make sure we have a valid username if(empty($username)){ # return invalid username throw new LoginException('Invalid username'); } else { $this->username = $username; }

# make sure we have a valid password if(empty($password)){ # return invalid username throw new LoginException('Invalid password'); }

# check that user exists if( ! $this->josso->userExists($this->username)){ throw new LoginException('Invalid username'); }

# check Josso with username and password $this->assertion = $this->josso->assertIdentityWithSimpleAuthentication($username, $password); if($this->josso->error){ throw new LoginException('Invalid username/password combination'); }

# resolve Authentication Assertion $this->token = $this->josso->resolveAuthenticationAssertion($this->assertion); if($this->josso->error){ throw new LoginException('Interal Error [Login]: '. LINE); }

$this->session = $this->josso->getSession($this->token); if($this->josso->error){ throw new LoginException('Interal Error [Login]: '. LINE); }

$this->user = $this->josso->findUserInSession($this->token); if($this->josso->error){ throw new LoginException('Interal Error [Login]: '. LINE); }

$this->cleanUpUser();

$this->roles = $this->josso->findRolesByUsername($this->username); if($this->josso->error){ throw new LoginException('Interal Error [Login]: '. LINE); }

$this->cleanUpRoles();

$this->user->sosPermissions =& $this->roles; }

public function createLoginFromToken($token){

$this->user = $this->josso->findUserInSession($token); if($this->josso->error){ throw new LoginException('Interal Error [Login]: '. LINE); }

$this->cleanUpUser();

$this->roles = $this->josso->findRolesByUsername($this->user->name); if($this->josso->error){ throw new LoginException('Interal Error [Login]: '. LINE); }

$this->cleanUpRoles();

$this->user->sosPermissions =& $this->roles; }

# get a Josso hashed version of a password public function getPassHash($password){ $passhash = $this->josso->getPassHash($password); return $passhash; }

# acquire roles for the user from josso public function getUserRoles(){ return $this->roles; }

# send the signal to Josso to signoff (closes all sessions) public function signoff($sessionid = null){ if( ! $sessionid && ! $this->session->id){ return false; }

if(!$sessionid){ if(!empty($this->session)){ if($this->josso->globalSignoff($this->session->id)){ return true; } } else { return false; } } else { if($this->josso->globalSignoff($sessionid)){ return true; } } return false; }

private function cleanUpUser(){ if(!empty($this->user)){ foreach($this->user->properties as $prop => $details){ $name = $details->name; if($pos = strpos($name, '.')){ $name = explode('.',$name); $name = $name[0] . ucwords($name[1]); } $this->user->$name = $details->value; } unset($this->user->properties); } }

private function cleanUpRoles(){ if(!empty($this->roles)){ foreach($this->roles as $key => $details){ $tmpRoles[$key] = $details->name; } $this->roles = $tmpRoles; } } } ?>[/php]

Josso Class

[php collapse="true"] <pre>class Josso {

var $SSOIdentityManager; var $SSOSessionManager; var $SSOIdentityProvider; var $JossoPashHash; var $error;

function Josso(){

// create the soapclients $this->SSOIdentityManager = new Soapclient(JOSSOSERVER .'/josso/services/SSOIdentityManager?wsdl', array('Trace' => 1)); $this->SSOSessionManager = new Soapclient(JOSSOSERVER .'/josso/services/SSOSessionManager?wsdl', array('trace' => 1)); $this->SSOIdentityProvider = new Soapclient(JOSSO_SERVER .'/josso/services/SSOIdentityProvider?wsdl', array('trace' => 1)); }

function accessSession($sessionid){ try{ $accessSession = $this->SSOSessionManager->accessSession($sessionid); // we expect a null return $accessSession; } catch(Exception $e){ $this->error = $e; return false; } }

// check if a user exists function userExists($username){ try { $userExists = $this->SSOIdentityManager->userExists($username); return true; } catch (Exception $e){ $this->error = $e; return false; } }

// assert a login function assertIdentityWithSimpleAuthentication($username, $password){ try{ $loginAssertion = $this->SSOIdentityProvider->assertIdentityWithSimpleAuthentication($username, $password); return $loginAssertion; } catch (Exception $e){ $this->error = $e; return false; } }

// check assertion and get session function resolveAuthenticationAssertion($loginAssertion){ try{ $session = $this->SSOIdentityProvider->resolveAuthenticationAssertion($loginAssertion); return $session; } catch (Exception $e){ $this->error = $e; return false; } }

// get session details function getSession($session){ try { $sessionDetails = $this->SSOSessionManager->getSession($session); return $sessionDetails; } catch (Exception $e){ $this->error = $e; return false; } }

// make sure the session we found belongs to our user function findUserInSession($session){ try { $userInSession = $this->SSOIdentityManager->findUserInSession($session); return $userInSession; } catch (Exception $e){ return false; } }

// not used function findUser($username){ try{ $userDetails = $this->SSOIdentityManager->findUser($username); return $userDetails; } catch (Exception $e){ return $e; } }

// get a users roles function findRolesByUsername($username){ try { $userRoles = $this->SSOIdentityManager->findRolesByUsername($username); return $userRoles; } catch (Exception $e){ $this->error = $e; return false; } }

function globalSignoff($session){ try { $signoff = $this->SSOIdentityProvider->globalSignoff($session); } catch (Exception $e){ $signoff = $e; } unset($_SESSION['josso']); return $signoff; }

function getPassHash($password){ try{ $result = $this->JossoPashHash->hash($password); return $result; } catch (Exception $e){ return $e; } }

}[/php]

That's It!

I hope I have at least in part helped with your quest to make logging people in through JOSSO more bearable.