Loading...

AuthStack Connector Framework for Laravel 5.1

The AuthStack Connector Framework is a Service Provider package, for Laravel, which works with SAML 2.0.

Installation

The following installation guide is applicable to the following AuthStack Connector Framework version (View repository).

Step 1

Add Buckhill's satis to your composer.json

"repositories": [
  { "type": "composer", "url": "https://satis.buckhill.co.uk" }
]

Step 2

Add "buckhill/laravel-5.1-saml-sp": "*" into composer.json or composer require "buckhill/laravel-5.1-saml-sp: "*"

Step 3

Create config/sso.php file. Use the file located in samples/sp_config.php and adjust it accordingly.

Make sure you adjust the config data properly - look at values like baseUrl, entityID and the metadata of the IDP you're connecting to. You will need to read your IDP's metadata and fill out it's entityID, x509 and the SSO/SLO enpoints in the config file.

You will need to fill out the 'keys' with valid x.509 certificate data.

You can generate a certificate using the following command in a bash shell:

openssl req -newkey rsa:2048 -new -x509 -days 3652 -nodes -out example.org.crt -keyout example.org.pem

The public key is entered as a string value, without the -----BEGIN CERTIFICATE----- and -----END CERTIFICATE----- part.

Example:

<?php

'x509' => 'MIIDXTCCAkWgAwIBAgIJAOjtFEt6oX//MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTcwMzI5MDgyMDMxWhcNMjcwMzI5MDgyMDMxWjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAzeNRu6+3PPsdhs0XR6SwFrIRHx9TIHl7BuRfPZI+3ooYZ+f0PAEowCUi
i2Bvlpf/0uOg5SA/thc+0wb1R35wag5G8LC9/g4NgH3rAycCj2gJ/zk02NXtiL/G
0RIoxwgd1iKC9KQmtrellLZnZ/yFlZFXVRrchtaMLgaiu7A9rdnq0imuRtUoeff1
zFCtln1gfHlUs5gGPq/dq+jEGvw0fvHsjpj8VCyG20v/5vgkqklWvCUwYu1rqt/7
v/03cm7s7WGm4tO0Zunk9eJoRYC9Ah5TOBGC8FOpo5Y6DvfLedE5cWM279R+7M4k
8DFQG62YDtZQmy9QilYBfUmjgwPWTwIDAQABo1AwTjAdBgNVHQ4EFgQUb8tV/LlK
lt9Jfztz3+XiQZqerpowHwYDVR0jBBgwFoAUb8tV/LlKlt9Jfztz3+XiQZqerpow
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEANo7PwBkoOijuCq3IYWxe
8flhH/VcXNkvVoPc60pQoFg+JLNq5+iOGRrADfPyc2WkJvAPFzPetdsvrDrS0xqh
U/Rm4kdvsjEzUTy/g0HHq+rkQZqEWGt1p8rtS/L/sSowx2sKedeCnkKmbfwFvasU
QuA240DgZXzaEb/ltvmUN832diAZslyJwG+83jvwU2/UUcT9bXWTwk4p1GC15HRV
WG8HQLXTC4Y3RunuH5sNlMtC5wsmyCax8clYOAA35xSxYDfMPa8KV+q8x5zu2UWi
N1PrXHgJSi+BNfwp//pWwT2rNCJ89DcYIs0nxHVSj91nmO4KTheu7WAlL5EknhSS
lQ==',

The private key needs to be completely loaded (including -----BEGIN PRIVATE KEY----- and -----END PRIVATE KEY------) parts, the easiest way is to copy the entire .pem file and include it into the config like so (to avoid any character escaping issues):

<?php
'private' => <<<EOF
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDN41G7r7c8+x2G
zRdHpLAWshEfH1MgeXsG5F89kj7eihhn5/Q8ASjAJSKLYG+Wl//S46DlID+2Fz7T
BvVHfnBqDkbwsL3+Dg2AfesDJwKPaAn/OTTY1e2Iv8bREijHCB3WIoL0pCa2t6WU
tmdn/IWVkVdVGtyG1owuBqK7sD2t2erSKa5G1Sh59/XMUK2WfWB8eVSzmAY+r92r
6MQa/DR+8eyOmPxULIbbS//m+CSqSVa8JTBi7Wuq3/u//TdybuztYabi07Rm6eT1
4mhFgL0CHlM4EYLwU6mjljoO98t50TlxYzbv1H7sziTwMVAbrZgO1lCbL1CKVgF9
SaODA9ZPAgMBAAECggEAWAhYjD3HxaVBrL/IsnNyb2HX/EyyiHIo7nt7VaJQi2rU
oKkHPxjnybCXIq0rSWLYmd2GkDHHzB4IWMbi3ZzsiAxuvL91nUl48HXmpMRrTdIY
ZC6bsBNYq14ErqRrFx8bUtIS2HPPsdS4UevkLwxEOf2ZL+R6YpUd/xgLQOFMniaI
foPhwYky9W32scVfu4tuV19RJ45v8Z4eSBrA7QEPaIZ8+mTcayuY4EFileHuHHtH
UkfrP1Z6KjQkqpX/LREJ8JX9dnjShEcNtooV1fHU+0itLjd6FvNh+J3kxVCtEnz9
t8Tixb1PmTnMSfh0ANjbKvK+czGI5Lr4E5SjbwSw0QKBgQD1v4QPLZNz4q23GPXC
Q/iCI69CHPlS5MNqriEZmiMYBuvFoYTkJr7Z/qjbuDwdZHmPyOtMwyOxw5enrj8o
tWrclIQX8dXWBlIifh38dPaAeggfYKsGEIyQ9gr/sndxvNKGQrWlJyZY0lCgEUSu
/wZSpFNVRAVAS/8ZRvrN/y3v7QKBgQDWeh092HUr3FQ8/Es13HBZ0Ty9JLz/wvcQ
1ecCoNdj0oE21Rb0o641kcufe//VXq8810cj5C4hwGqiUaGcelLN4R2ZWhFRkXRQ
M9YRXwE6tmhiAUW0x9QrlrljE7/3xl4XwlwhCz33//vsujEvCC5/Ud1IyxihvGUU
CkR3BMZ/qwKBgGUpO1GML2DK9TukGLapiEj6K5EJoFDRPuhRWerSGpQvdSrbvHq2
wGW4gQZBpu1qiOf5i3MD+VOZ8nniLrmxRJYcxOueb6o02+a7B9j+xOJKWcGg54YN
le+ueQSdELJPSlJeb6vWm+CAYxQhR6bJ8G5gmrVE1OyM3CwpneDipKRZAoGAChvt
Xunh8/RJoCpAHUTLouAi3cNqiR+WZ5u9bLlKDbFxV7VJhLRmVK4Pi+/bSiJRXivD
daSerAaWwBna5TY6yutuarj9EfwqIFGhKGZy92J7nwryTygQDxHmoQ3gQXx/GN2X
XBNck2Dkbe8EvHPFRUkFhhXUjmMD3KLzQSzfcksCgYEA0oLg+lLuxuwLYQqW5flA
btcrUJrolU+tfJtHz8FZOc0gBCwvvCRQOfKoUjsIUD3AQXQqbR3KCtyFNwqxFp9D
nG7H9Qn9WPgTet6B6vMVS3+h/WyZKzToEN7nRteYV9PAz5a2ijI3+zdGJdtco+v6
SewoVQXnCrOkG9i/Uj2SHQg=
-----END PRIVATE KEY-----

EOF
,

Step 4

Open config/app.php and add the following to providers array:

'providers' => [
    Buckhill\LaravelSAML\Providers\AuthenticatedUserProvider::class,
    Buckhill\LaravelSAML\Providers\SAMLRoutesProvider::class,
]

Step 5

If everything is setup/configured correctly, you will now have the following routes available:

{base_url}/sso/saml2.0/metadata.xml - shows your SP metadata (try changing config values - keys, SP entity ID etc to see changes to the metadata)

{base_url}/sso/saml2.0/authenticate - starts the authentication flow (redirects to IDP if configured properly)

{base_url}/sso/saml2.0/acs - assertion consumer service endpoint (incoming SAML requests from the IDP end up here)

Step 6

How to modify the behavior after the assertion consumer service finishes its job:

You can specify a different route / controller for ACS:

  • open config/sso.php
  • find SP.routes key
  • look for SP.routes.acs and change the path to controller. Default one is Buckhill\LaravelSAML\Http\Controllers\SSO
  • Create your controller in App\Http\Controllers and extend the default controller

Example on how to communicate to Buckhill's own Customer Service with extended ACS:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use function AuthStack\SP\authn;
use Illuminate\Support\Facades\Log;
use AuthStack\SP\AttributeCollection;
use Buckhill\CustomerServerClient\Facade\CustomerServer;
use Buckhill\LaravelSAML\Http\Controllers\SSO as SSOController;

class SSO extends SSOController
{
    /**
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
     */
    public function acs(Request $request)
    {
        return parent::acs($request);
    }

    /**
     * @param Request $request
     * @param AttributeCollection $collection
     */
    protected function afterACS(Request $request, AttributeCollection $collection)
    {
        $data = [
            'type_id'           => 3,
            'signup_id'         => 1,
            'social_id'         => $collection->getNameIdValue(),
            'email'             => $collection->getNameIdValue(),
            'full_name'         => sprintf("%s %s", $collection->get('givenname')->getFirstAttributeValue(), $collection->get('sn')->getFirstAttributeValue()),
            'additional'        => [
                'organization'      => $collection->get('o')->getFirstAttributeValue(),
                'country'           => $collection->get('st')->getFirstAttributeValue(),
                'city'              => $collection->get('l')->getFirstAttributeValue(),
                'postalCode'        => $collection->get('postalcode')->getFirstAttributeValue(),
                'postaladdress'     => $collection->get('postaladdress')->getFirstAttributeValue(),
                'tel'               => $collection->get('telephonenumber')->getFirstAttributeValue()
            ]
        ];

        Log::info("SAML response returned", ['request' => $request->all()]);

        /** @var  $customer \Buckhill\CustomerServerClient\Model\Customer */
        $customer = CustomerServer::retrieve($data);

        $request->session()->put('profile', $customer->toArray());

        session()->put(config('sso.SP.sessionKeyName'), $customer->toArray());
    }
}

Step 7

Add custom route filtering if you need SAML protected routes.

You can do this via the available \Buckhill\LaravelSAML\Http\Middleware\Authenticated middleware, which will allow access only with a valid SAML session.

If you will be forwarding the SAML session (checking the received attributes and creating/loggin in users via your applications user system as per the attributes) you probably won't need this - just check the attributes and let your user system assume control from there in the appropriate place (most probably after ACS function in a controller that will extend the provided SSO controller).


Previous Article

Connector for PHP

We're happy to talk

Our offices are open 8.30am - 7pm GMT, Monday to Friday - but you can always contact us via email. When we receive your email during opening hours, we aim to respond within 30 minutes or less. Should your email reach us out of hours, we will contact you when the office re-opens.

You can contact us using live chat