[Code coverage details](http://coverage.buckhill.com.hr/authstack/sp/coverage)

[Treemap of code coverage](http://coverage.buckhill.com.hr/authstack/sp/treemap)

# AuthStack Service Provider library

This library consumes SAMLResponse and parses it into an object that returns statements (attributes) and `NameId`


# How to use 

For the library to work, you must supply *valid* configuration. More on configuration under [Configuration](#configuration) section


### Consuming a SAMLResponse

```php
<?php

use AuthStack\SP\ServiceProvider;

$configuration = [
	'baseUrl' => 'http://your.site.com',
	'IdP' => [
		sha1('https://www.authstack.co.uk') => [
			// EntityId of IdP
			'entityId'      => 'https://www.authstack.co.uk',

			// Single Sign On service URL and binding. Binding can be Redirect (GET method) or POST
			'SSO' => [
				'url' => 'https://authstack/saml2.0/sso',
				'binding' => SamlConstants::BINDING_SAML2_HTTP_POST
			],

			'SLO' => [
				'url'   => 'https://authstack/saml2.0/slo',
				'binding' => SamlConstants::BINDING_SAML2_HTTP_POST
			],

			// IdP's public key, saved as encoded x.509 certificate
			'x509' => ' ',

			// If true, then service provider signs the requests so that IdP can prove the authenticity of message origin
			'wantsSignedRequests' => true
		]
	]
];


// 1st parameter = configuration for the SP
// 2nd parameter = IdP's entityId, that's being used to look up IdP info in config

$sp = new ServiceProvider($config, 'https://www.authstack.co.uk');

try
{
	/** Returns a collection with attribute names and values */
	$collection = $sp->consume();
	
	// Returns an associative array, key is the attribute name
	$attributes = $collection->toArray();
	
	// If you want multi-valued attributes to be returned with all their values, pass true to the toArray() method
	$multivalued = $collection->toArray(true);
	
	// Returns an instance of \LightSaml\Model\Assertion\Attribute
	// This is useful for multi-valued attributes (arrays)
	$memberof = $collection->get('memberof');
	
	// Returns the value of NameId
	$nameid = $collection->getNameIdValue();
	
	// Returns the format of NameId
	$format = $collection->getNameIdFormat();
	
	// Returns the RelayState
	$rstate = $collection->getRelayState();
}
catch(Exception $e)
{
	// Check for the exception type in order to determine what exactly went wrong.
	// Alternatively, you can just read the message to see what happened
	
	echo $e->getMessage();
}
```

Doing the same, using helper functions 

```php
<?php

use function AuthStack\SP\authn;

$config = [];
$idp = 'https://www.authstack.co.uk';

try
{
	$collection = authn($config, $idp)->consume();
	
	$attributes = $collection->toArray();
	
	$nameid = $collection->getNameIdValue();
	
	$format = $collection->getNameIdFormat();
}
catch(\Exception $e)
{
}


```


### Exposing Service Provider Metadata 

```php
<?php

use function AuthStack\SP\metadata;

$config = [];

$metadata = metadata($config);

$xml = $metadata->toXml();

header('Content-Type: application/xml');

echo $xml;
```

### Creating the AuthN (authentication request)

This snippet assumes you have provided correct configuration

```php
<?php

use AuthStack\SP\ServiceProvider;

// Assumes that $config is valid configuration
$config = [];

$sp = new ServiceProvider($config, 'https://www.authstack.co.uk');

/** @var $authn AuthStack\SP\Requests\AuthN */
$authn = $sp->authn();

// Depending on config, the request method towards IdP can be POST or GET. There's a utility method that does
// this for us, called initiate. 

$authn->initiate();

// Do not forget exit; - we need this because we're sending headers and we don't want anything after initiate() to execute
exit;

```

Doing the same using helper functions 

```php
<?php

use function AuthStack\SP\authn;

$config = [];
$idp = 'https://www.authstack.co.uk';


authn($config, $idp)->initiate();

```


### Creating/Initiating a LogoutRequest 

```php
<?php

use function AuthStack\SP\logout;

$config = [];
$idp = 'https://www.authstack.co.uk';

logout($config, $idp)->initiate();

```

### Creating a Logout Request, saving information to database and sending it to IdP

```php
<?php

use function AuthStack\SP\logout;

$config = [];
$idp = 'https://www.authstack.co.uk';

$logout = logout($config, $idp);

$request_id = $logout->getRequestId();

// Save to database

// Done saving to database

$logout->initiate();

```


### Consuming a LogoutRequest or LogoutResponse


# Configuration

Configuration is handled by `Buckhill/config` package, which accepts an array as a parameter and lets you use dot notation to access the keys.
The configuration can be serialized to JSON, saved to database/NoSQL and then retrieved when required, or you can keep the configuration in a file.

The configuration array is pretty extensive and instead of commenting each feature on its own, we'll show the whole config array and explain what each key means in the comments


```php
<?php

$config = [

	// The URL of your service provider. You can include subdirectories etc, but DO NOT end with trailing slash
	'baseUrl' => 'http://www.your-service-provider-url.com',

	// An array of known / configured SAML Identity Providers	
	'IdP' => [
	
		// Each IdP in config array is "indexed" by its EntityID. Please, sha1() EntityID of the IdP you're adding here 
		sha1('https://www.authstack.co.uk/saml2.0/idp') => [

			// EntityId of IdP - we will be checking for this in the SAML responses so it's mandatory you provide correct Entity ID
			'entityId'      => 'https://www.authstack.co.uk/saml2.0/idp',

			// Single Sign On service URL and binding. Binding can be Redirect (GET method) or POST
			'SSO' => [
				'url' => 'https://www.authstack.co.uk/saml2.0/sso',
				'binding' => SamlConstants::BINDING_SAML2_HTTP_POST
			],

			// Single Log Out service
			'SLO' => [
				'url'   => 'https://www.authstack.co.uk/saml2.0/slo',
				'binding' => SamlConstants::BINDING_SAML2_HTTP_POST
			],

			// IdP's public key, saved as encoded x.509 certificate
			// Don't provide paths to files or use file_get_contents - reason for that is that configuration is supposed to be serializable
			// to JSON and saved, so that clustering is easy (multiple php-fpm nodes can read from MySQL cluster, so it becomes irrelevant which node does the job)
			// Therefore, provide the actual x509 as a string
			'x509' => ' ',

			// If true, then service provider signs the requests so that IdP can prove the authenticity of message origin
			// For signing to work, you must have IdP's public key (usually delivered via x.509 certificate exposed in metadata)
			'wantsSignedRequests' => true		
		]	
	],

	// Service Provider configuration 
	'SP' => [
	
		// Controls what gets validated to assert that SAML response is valid
		'validate' => [
		
			// If true, checks for presence of <samlp:Status> and tries to verify that its value is urn:oasis:names:tc:SAML:2.0:status:Success
			// If false, check is skipped
			'status' => true,

			// Checks whether the issuer matches IdP.entityId config key (verifies that actual and expected values are the same)
			// If false, check is skipped
			'issuer' => true,

			// Checks whether the destination in SAMLResponse matches the destination where this message is processed (simple URI comparison)
			// If false, check is skipped
			'destination' => true,
			
			// Validates whether the assertion expired
            // Below configuration checks whether the message is older than 1 minute or not. If it is, then it's not valid
            'lifetime' => true,

            // Upper time boundary (not AFTER 1 minute)
            'upper'     => '+1 minute',

            // Lower time boundary (not BEFORE 1 minute)
            'lower'     => '-1 minute'
		],

		// Entity ID or "Name" of our Service Provider. This is used for verifying messages received by IdP
		'entityId'      => 'http://sp',

		// Format in which we want to receive NameId back
		// For full list, check the LightSaml\SamlConstants class
		// NameId is equivalent to primary key in relational databases. 
		// IdP will deliver the NameId value and NameIdFormat 
		'nameIdFormat' => \LightSaml\SamlConstants::NAME_ID_FORMAT_EMAIL,

		// If true, then library verifies the signature in messages received from IdP, to prove authenticity of message origin
		'wantsSignedMessages' => true,

		// If true, each assertion will be signed using IdP's private key
		'wantsSignedAssertions' => false,

		// If true, each assertion will be encrypted on the IdP's side, using SP's public key
		// SP requires a private key to decrypt them. Public key will be delivered to the IdP in metadata exchange
		'wantsEncryptedAssertions' => true,

		// Location of the service which consumes responses sent by IdP
		// Information specified here is included in SP metadata
		// If your webiste doesn't use "pretty" urls, then simply include the path to the URL to the script which will be using this library
		'AssertionConsumerService' => [
			// Binding or method. In this case, method is HTTP POST, which means if someone sends a
			// POST request to http://sp/saml/acs then the library will be invoked in order to parse the message
			'binding' => SamlConstants::BINDING_SAML2_HTTP_POST,
			'location' => '/saml/acs'
		],

		// SLO (Single Log Out) is a service which logs the user out. In SSO environment, a user can be
		// logged on to multiple services and a Single Log Out should log the user out from all the services.
		// That means that each service is supposed to receive a SLO request, log the user out and then return
		// them back to IdP so that IdP can coordinate log out from other services. That's why it's important
		// to have defined Single Log Out service (defined means to actually have it working)
		'SLO' => [
			'binding' => SamlConstants::BINDING_SAML2_HTTP_POST,
			'location' => '/saml/slo'
		],

		// Keys used for signing / encrypting messages. These can be empty if SP and IdP are configured
		// to communicate without signing / encrypting messages.
		// If that's the case, then Idp <> SP communication should go over TLS (https)
		'keys' => [

			// Keypair used for signing purposes
			'signing' => [

				// Value of x.509 certificate
				// This is base64 encoded value, WITHOUT the ---BEGIN PUBLIC KEY--- 
				'x509' => '',

				// Value of private key
				'private' => '',

				// Passphrase for the private key, if any
				'passphrase' => '',

				// Hash function for signature algorithm
				'algorithm' => \RobRichards\XMLSecLibs\XMLSecurityKey::RSA_SHA256
			],

			// Keypair used for encrypting assertions
			'encryption' => [

				// Value of x.509 certificate
				'x509' => '',

				// Value of private key
				'private' => '',

				// Passphrase for the private key, if any
				'passphrase' => '',

				// Hash function for signature algorithm
				'algorithm' => \RobRichards\XMLSecLibs\XMLSecurityKey::RSA_SHA256
			]
		]
	]
];



```

