I've integrated SimpleSAMLphp with my application, however it only works on a production environment as there is no connection to the IdP servers elsewhere. How can I continue working on the development environment on things that require authentication?
I've written a wrapper class that exposes the necessary methods to the SimpleSAML_Auth_Simple
class. The relevant code is as follows:
<?php
// (assume autoloading)
$saml = new SAMLWrapper('name-of-sp');
$saml->requireAuthentication('https://[::1]/app/saml-controller.php?callback=1');
$userAttributes = $saml->getAttributes();
// rest of application code below...
class SAMLWrapper extends IAuthentication
{
private $as;
public function __construct($sp) {
require_once('/var/simplesamlphp/lib/_autoload.php');
// THIS PATH DOES NOT EXIST ON DEV
$this->as = new \SimpleSAML_Auth_Simple($sp);
}
public function requireAuthentication($callback) {
$this->as->requireAuth(array('ReturnTo' => $callback));
}
public function getAttributes() {
return $this->as->getAttributes();
}
}
I've considered writing a dummy wrapper like this:
class DummySAML extends IAuthentication
{
private $attrs;
public function __construct(array $attrs) {
$this->attrs = $attrs;
}
public function requireAuthentication() {
return;
}
public function getAttributes() {
return $this->attrs;
}
}
However this means I have to switch between the SAMLWrapper
and DummySAML
class on all the pages requiring authentication:
if (getenv('SLIM_MODE') === 'DEV') {
// instantiate DummySAML with test attributes
} else {
// instantiate SAMLWrapper with service provider name
}
Is there an easier and better way of doing this?
One option would be to move the env-based switching inside a single wrapper class. One immediately obvious downside is that your test attributes would need to either be hard-coded inside the class, or always passed to the constructor even in production. Otherwise you wouldn't be able to support both scenarios with a single constructor.
In my own apps, I would probably obtain the authentication wrapper from a dependency injection container, registering a factory that checks the environment and returns an instance of the appropriate class (real or dummy). If you're not already using DI, migrating could be a real pain, but you could always create a one-off static factory that handles the instantiation of the appropriate wrapper to reduce the amount of boilerplate at the top of each file.