SAML ECP client implementation in PHP
As described in the current specification draft, the SAML V2.0 Enhanced Client or Proxy (ECP) profile is a SSO profile for use with HTTP, and clients with the capability to directly contact a principal's identity provider(s) without requiring discovery and redirection by the service provider, as in the case of a browser. It is particularly useful for desktop or server-side HTTP clients.
This library tries to follow the ECP profile specification. Currently, it doesn't support the „Holder of Key“ and „Channel Bindings“ features. The status of the library is „highly experimental“. It is not 100% ready and it hasn't been tested in different environments.
- PHP >= 5.3
- Zend Framework >= 2.*
- Shibboleth SP/IdP
If you use composer in your project, you can just add the following requirement to your
Otherwise, clone the repository and configure your autoloader to look for the Saml namespace in the
lib/ directory of the repository.
use Saml\Ecp\Flow; use Saml\Ecp\Client\Client; use Saml\Ecp\Discovery\Method\StaticIdp; use Saml\Ecp\Authentication\Method\BasicAuth; $flow = new Flow\Basic(); $client = new Client(array( 'http_client' => array( 'options' => array( 'cafile' => '/etc/ssl/certs/tcs-ca-bundle.pem' ) ) )); $flow->setClient($client); $authenticationMethod = new BasicAuth(array( 'username' => 'user', 'password' => 'passwd' )); $discoveryMethod = new StaticIdp(array( 'idp_ecp_endpoint' => 'https://idp.example.org/idp/profile/SAML2/SOAP/ECP' )); $response = $flow->authenticate('https://sp.example.com/secure', $discoveryMethod, $authenticationMethod);
The Client object is responsible for the actual work - sending requests and validating responses. The Flow object uses the client object to issue requests in the apropriate order. The authenticate() method performs the whole ECP flow, when the client tries to access the protected resource and then it is redirected to the IdP for authentication. Besides the resource URL, the authenticate() method needs a discovery method object, which determines the IdP to use for authentication and an authentication method object, which adjusts the authentication request.
In this case the discovery method ( StaticIdP ) just returns the IdP endpoint. The authentication method ( BasicAuth ) adjusts the request to perform a HTTP Basic authentication based on the provided credentials.
Shibboleth SP supports the ECP profile, but it needs to be „switched on“ in the SessionInitiator configuration:
<SessionInitiator id="ECP" type="SAML2" Location="/ECP" ECP="true" entityID="https://idp.example.org/idp/shibboleth"> </SessionInitiator>
In case this is not the default session initiator (as the above example), you need to configure Apache to use the right session initiator for the secured resource:
<Location /secure> AuthType shibboleth ShibRequestSetting requireSessionWith ECP Require valid-user </Location>
The IdP supports the ECP profile "out of the box". Currently the ECP profile handler requires external web server based authentication. Basically, it means thet you need to protect the ECP profile handler endpoint with some kind of HTTP Basic authentication in the same way as in case of using the RemoteUser login handler.
<Location /idp/profile/SAML2/SOAP/ECP> AuthType Basic AuthName "IdP ECP endpoint authentication" AuthBasicProvider ldap AuthLDAPURL "ldap://127.0.0.1/o=example.org" AuthzLDAPAuthoritative off require valid-user </Location>
This library is more a framework than a ready to use application. There are numerous environments and use cases and it's not possible to cover them all „out of the box“. That is why the library has been designed to be as flexible and extensible as possible. Some parts may be easily exchanged with alternative implementations or extended with additional features.
The Saml\Ecp\Client\Client object uses internally the Zend\Http\Client object with the cURL adapter ( Zend\Http\Client\Adapter\Curl ). For security reasons the peer and host validation is on by default (
CURLOPT_SSL_VERIFYPEER = true,
CURLOPT_SSL_VERIFYHOST = 2). You have to pass one of the following options:
- cafile - path to the file containing CA certificates used for peer/host validation
- capath - path the the directory contiaining CA certificates used for peer/host validation
You can also pass options directly to the HTTP client and the cURL adapter through these options:
- zend_client_options - array of options as described in ZF2 manual
- curl_adapter_options - array of options as described in ZF2 manual
$client = new \Saml\Ecp\Client\Client(array( 'http_client' => array( 'options' => array( 'cafile' => '/etc/ssl/certs/ca-bundle.crt' ), 'zend_client_options' => array( 'useragent' => 'My ECP Client v0.1' ), 'curl_adapter_options' => array( CURLOPT_FORBID_REUSE => true ) ) ));
The Client object uses the Saml\Ecp\Client\HttpClientFactory to create the HTTP client object bases on the „http_client“ option. Instead of passing the „http_client“ option to the Client object, you can explicitly create the Zend\Http\Client object and inject it:
$httpClient = new \Zend\Http\Client(); $httpClient->setOptions(array( // options )); $adapter = new \Zend\Http\Client\Adapter\Curl(); $adapter->setOptions(array( // options )); $httpClient->setAdapter($adapter); $client = new \Saml\Ecp\Client\Client(); $client->setHttpClient($httpClient);
You can write your own IdP discovery method by implementing the Saml\Ecp\Discovery\Method\MethodInterface.
You can code another authentication method by implementing the Saml\Ecp\Authentication\Method\MethodInterface.
If you need to implement alternative request objects, you can extend the Saml\Ecp\Request\AbstractRequest object or just implement the Saml\Ecp\Request\RequestInterface. You will also have to implement your own request factory by implementing the Saml\Ecp\Request\RequestFactoryInterface and inject it into the Saml\Ecp\Client\Client object so the client can use your alternative request objects instead of the „standard“ ones.
Similar to the requests, you can write your own by extending the abstract response class ( Saml\Ecp\Response\AbstractResponse ) or by implementing the response interface ( Saml\Ecp\Response\ResponseInterface ). Additionaly you need to write an alternative response factory implementing the Saml\Ecp\Response\ResponseFactoryInterface.
Response validation is achieved through validators created by the Saml\Ecp\Response\Validator\ValidatorFactory. The validators must implement the Saml\Ecp\Response\Validator\ValidatorInterface and the validator factory must implement the Saml\Ecp\Response\Validator\ValidatorFactoryInterface. The validator factory has to be injected into the client object ( Saml\Ecp\Client\Client ).