|
| 1 | +[](https://packagist.org/packages/codegreencreative/laravel-samlidp) |
| 2 | +[](https://packagist.org/packages/codegreencreative/laravel-samlidp) |
| 3 | + |
| 4 | +[Buy me a coffee](https://www.buymeacoffee.com/upwebdesign) :coffee: |
| 5 | + |
| 6 | +# Laravel SAML IdP |
| 7 | + |
| 8 | +This package allows you to implement your own Identification Provider (idP) using the SAML 2.0 standard to be used with supporting SAML 2.0 Service Providers (SP). |
| 9 | + |
| 10 | +Starting in version ^5.1, Laravel 9 is supported. |
| 11 | +Starting in version ^5.2.4, Laravel 10 is supported. |
| 12 | + |
| 13 | +In this version we will be allowing for Laravel ^7.0 or ^8.0. |
| 14 | + |
| 15 | +If you are looking for Laravel ^5.6 see [v1.0](https://github.com/codegreencreative/laravel-samlidp/tree/1.0) |
| 16 | + |
| 17 | +If you are looking for Laravel ^6.0 use [v2.0](https://github.com/codegreencreative/laravel-samlidp/tree/2.0) |
| 18 | + |
| 19 | +## Installation |
| 20 | + |
| 21 | +```shell |
| 22 | +composer require codegreencreative/laravel-samlidp |
| 23 | +``` |
| 24 | + |
| 25 | +# Configuration |
| 26 | + |
| 27 | +```shell |
| 28 | +php artisan vendor:publish --tag="samlidp_config" |
| 29 | +``` |
| 30 | + |
| 31 | +FileSystem configuration |
| 32 | + |
| 33 | +```php |
| 34 | +// config/filesystem.php |
| 35 | + |
| 36 | +'disks' => [ |
| 37 | + |
| 38 | + ... |
| 39 | + |
| 40 | + 'samlidp' => [ |
| 41 | + 'driver' => 'local', |
| 42 | + 'root' => storage_path() . '/samlidp', |
| 43 | + ] |
| 44 | +], |
| 45 | +``` |
| 46 | + |
| 47 | +Use the following command to create a self signed certificate for your IdP. If you change the certname or keyname to anything other than the default names, you will need to update your `config/samlidp.php` config file to reflect those new file names. |
| 48 | + |
| 49 | +```shell |
| 50 | +php artisan samlidp:cert [--days <days> --keyname <name> --certname <name>] |
| 51 | +``` |
| 52 | + |
| 53 | +```shell |
| 54 | +Options: |
| 55 | + --days=<days> Days to add for the expiration date [default: 7800] |
| 56 | + --keyname=<name> Name of the certificate key file [default: key.pem] |
| 57 | + --certname=<name> Name of the certificate file [default: cert.pem] |
| 58 | +``` |
| 59 | + |
| 60 | +Optionally, you can set the certificate and key using two environment variables: `SAMLIDP_CERT` and `SAMLIDP_KEY`. |
| 61 | + |
| 62 | +## Usage |
| 63 | + |
| 64 | +Within your login view, probably `resources/views/auth/login.blade.php` add the SAMLRequest directive beneath the CSRF directive: |
| 65 | + |
| 66 | +```php |
| 67 | +@csrf |
| 68 | +@samlidp |
| 69 | +``` |
| 70 | + |
| 71 | +The SAMLRequest directive will fill out the hidden input automatically when a SAMLRequest is sent by an HTTP request and therefore initiate a SAML authentication attempt. To initiate the SAML auth, the login and redirect processes need to be intervened. This is done using the Laravel events fired upon authentication. |
| 72 | + |
| 73 | +## Config |
| 74 | + |
| 75 | +After you publish the config file, you will need to set up your Service Providers. The key for the Service Provider is a base 64 encoded Consumer Service (ACS) URL. You can get this information from your Service Provider, but you will need to base 64 encode the URL and place it in your config. This is due to config dot notation. |
| 76 | + |
| 77 | +You may use this command to help generate a new SAML Service Provider: |
| 78 | + |
| 79 | +```shell |
| 80 | +php artisan samlidp:sp |
| 81 | +``` |
| 82 | + |
| 83 | +Example SP in `config/samlidp.php` file: |
| 84 | + |
| 85 | +```php |
| 86 | +<?php |
| 87 | + |
| 88 | +return [ |
| 89 | + // The URI to your login page |
| 90 | + 'login_uri' => 'login', |
| 91 | + // The URI to the saml metadata file, this describes your idP |
| 92 | + 'issuer_uri' => 'saml/metadata', |
| 93 | + // List of all Service Providers |
| 94 | + 'sp' => [ |
| 95 | + // Base64 encoded ACS URL |
| 96 | + 'aHR0cHM6Ly9teWZhY2Vib29rd29ya3BsYWNlLmZhY2Vib29rLmNvbS93b3JrL3NhbWwucGhw' => [ |
| 97 | + // ACS URL of the Service Provider |
| 98 | + 'destination' => 'https://example.com/saml/acs', |
| 99 | + // Simple Logout URL of the Service Provider |
| 100 | + 'logout' => 'https://example.com/saml/sls', |
| 101 | + // SP certificate |
| 102 | + // 'certificate' => '', |
| 103 | + // Turn off auto appending of the idp query param |
| 104 | + // 'query_params' => false, |
| 105 | + // Turn off the encryption of the assertion per SP |
| 106 | + // 'encrypt_assertion' => false |
| 107 | + ], |
| 108 | + ], |
| 109 | + // List of guards saml idp will catch Authenticated, Login and Logout events (thanks @abublihi) |
| 110 | + 'guards' => ['web'], |
| 111 | +]; |
| 112 | +``` |
| 113 | + |
| 114 | +### Setting the service provider certificate |
| 115 | + |
| 116 | +There are three options to set the service provider certificate. |
| 117 | + |
| 118 | +1. Provide the certificate as a string: |
| 119 | + |
| 120 | +```php |
| 121 | +<?php |
| 122 | + |
| 123 | +return [ |
| 124 | + // ... |
| 125 | + 'sp' => [ |
| 126 | + // Base64 encoded ACS URL |
| 127 | + 'aHR0cHM6Ly9teWZhY2Vib29rd29ya3BsYWNlLmZhY2Vib29rLmNvbS93b3JrL3NhbWwucGhw' => [ |
| 128 | + // ... |
| 129 | + // SP certificate |
| 130 | + // 'certificate' => "-----BEGIN CERTIFICATE-----\nb3BlbnNzaC1rZXktdjEA...LWdlbmVyYXRlZC1rZXkBAgM\n-----END CERTIFICATE-----" |
| 131 | + ], |
| 132 | + ], |
| 133 | + // ... |
| 134 | +]; |
| 135 | +``` |
| 136 | + |
| 137 | +2. Load from a variable within the `.env` file. |
| 138 | + You can choose an appropriate variable name that best matches your projects requirements. |
| 139 | + |
| 140 | +```php |
| 141 | +<?php |
| 142 | + |
| 143 | +return [ |
| 144 | + // ... |
| 145 | + 'sp' => [ |
| 146 | + // Base64 encoded ACS URL |
| 147 | + 'aHR0cHM6Ly9teWZhY2Vib29rd29ya3BsYWNlLmZhY2Vib29rLmNvbS93b3JrL3NhbWwucGhw' => [ |
| 148 | + // ... |
| 149 | + // SP certificate |
| 150 | + // 'certificate' => env('SAML_SP_CERTIFICATE', '') |
| 151 | + ], |
| 152 | + ], |
| 153 | + // ... |
| 154 | +]; |
| 155 | +``` |
| 156 | + |
| 157 | +3. Load the certificate from a file: |
| 158 | + |
| 159 | +```php |
| 160 | +<?php |
| 161 | + |
| 162 | +return [ |
| 163 | + // ... |
| 164 | + 'sp' => [ |
| 165 | + // Base64 encoded ACS URL |
| 166 | + 'aHR0cHM6Ly9teWZhY2Vib29rd29ya3BsYWNlLmZhY2Vib29rLmNvbS93b3JrL3NhbWwucGhw' => [ |
| 167 | + // ... |
| 168 | + // SP certificate |
| 169 | + // 'certificate' => 'file://' . storage_path('samlidp/service-provider.pem') |
| 170 | + ], |
| 171 | + ], |
| 172 | + // ... |
| 173 | +]; |
| 174 | +``` |
| 175 | + |
| 176 | +## Log out of IdP after SLO |
| 177 | + |
| 178 | +If you wish to log out of the IdP after SLO has completed, set `LOGOUT_AFTER_SLO` to `true` in your `.env` perform the logout action on the Idp. |
| 179 | + |
| 180 | +``` |
| 181 | +// .env |
| 182 | +
|
| 183 | +LOGOUT_AFTER_SLO=true |
| 184 | +``` |
| 185 | + |
| 186 | +## Redirect to SLO initiator after logout |
| 187 | + |
| 188 | +If you wish to return the user back to the SP by which SLO was initiated, you may provide an additional query parameter to the `/saml/logout` route, for example: |
| 189 | + |
| 190 | +``` |
| 191 | +https://idp.com/saml/logout?return_to=mysp.com |
| 192 | +``` |
| 193 | + |
| 194 | +After all SP's have been logged out of, the user will be redirected to `mysp.com`. For this to work properly you need to add the `sp_slo_redirects` option to your `config/samlidp.php` config file, for example: |
| 195 | + |
| 196 | +```php |
| 197 | +<?php |
| 198 | + |
| 199 | +// config/samlidp.php |
| 200 | + |
| 201 | +return [ |
| 202 | + // If you need to redirect after SLO depending on SLO initiator |
| 203 | + // key is beginning of HTTP_REFERER value from SERVER, value is redirect path |
| 204 | + 'sp_slo_redirects' => [ |
| 205 | + 'mysp.com' => 'https://mysp.com', |
| 206 | + ], |
| 207 | +]; |
| 208 | +``` |
| 209 | + |
| 210 | +## Attributes (optional) |
| 211 | + |
| 212 | +Service providers may require more additional attributes to be sent via assertion. Its even possible that they require the same information but as a different Claim Type. |
| 213 | + |
| 214 | +By Default this package will send the following Claim Types: |
| 215 | + |
| 216 | +`ClaimTypes::EMAIL_ADDRESS` as `auth()->user()->email` |
| 217 | +`ClaimTypes::GIVEN_NAME` as `auth()->user()->name` |
| 218 | + |
| 219 | +This is because Laravel migrations, by default, only supply email and name fields that are usable by SAML 2.0. |
| 220 | + |
| 221 | +To add additional Claim Types, you can subscribe to the Assertion event: |
| 222 | + |
| 223 | +`CodeGreenCreative\SamlIdp\Events\Assertion` |
| 224 | + |
| 225 | +Subscribing to the Event: |
| 226 | + |
| 227 | +In your `App\Providers\EventServiceProvider` class, add to the already existing `$listen` property... |
| 228 | + |
| 229 | +```php |
| 230 | +protected $listen = [ |
| 231 | + 'App\Events\Event' => [ |
| 232 | + 'App\Listeners\EventListener', |
| 233 | + ], |
| 234 | + 'CodeGreenCreative\SamlIdp\Events\Assertion' => [ |
| 235 | + 'App\Listeners\SamlAssertionAttributes' |
| 236 | + ] |
| 237 | +]; |
| 238 | +``` |
| 239 | + |
| 240 | +Sample Listener: |
| 241 | + |
| 242 | +```php |
| 243 | +<?php |
| 244 | + |
| 245 | +namespace App\Listeners; |
| 246 | + |
| 247 | +use LightSaml\ClaimTypes; |
| 248 | +use LightSaml\Model\Assertion\Attribute; |
| 249 | +use CodeGreenCreative\SamlIdp\Events\Assertion; |
| 250 | + |
| 251 | +class SamlAssertionAttributes |
| 252 | +{ |
| 253 | + public function handle(Assertion $event) |
| 254 | + { |
| 255 | + $event->attribute_statement |
| 256 | + ->addAttribute(new Attribute(ClaimTypes::PPID, auth()->user()->id)) |
| 257 | + ->addAttribute(new Attribute(ClaimTypes::NAME, auth()->user()->name)); |
| 258 | + } |
| 259 | +} |
| 260 | +``` |
| 261 | + |
| 262 | +## Digest Algorithm (optional) |
| 263 | + |
| 264 | +See `\RobRichards\XMLSecLibs\XMLSecurityDSig` for all digest options. |
| 265 | + |
| 266 | +```php |
| 267 | +<?php |
| 268 | + |
| 269 | +return [ |
| 270 | + // Defind what digital algorithm you want to use |
| 271 | + 'digest_algorithm' => \RobRichards\XMLSecLibs\XMLSecurityDSig::SHA1, |
| 272 | +]; |
| 273 | +``` |
| 274 | + |
| 275 | +[Buy me a coffee](https://www.buymeacoffee.com/upwebdesign) :coffee: |
0 commit comments