Skip to content

Commit

Permalink
Merge branch 'release/1.2.0'
Browse files Browse the repository at this point in the history
  • Loading branch information
breart committed Jun 20, 2019
2 parents d282476 + c02f0d2 commit 011ac0d
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 96 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## [1.2.0] - 2019-06-20

### Added
- Refactored the way of resolving identity provider, now we take it from URL
- Implemented helper saml_idp_key() to retrieve a resolved IdP
- Implemented helpers saml_url(), saml_route() to generate SSO-friendly links (fx. on emails)

### Fixed
- Fixed redirecting to a custom URL on login request using the `returnTo` query parameter

### Removed
- Removed referrer URLs from config parameters

## [1.1.3] - 2019-02-25

### Added
Expand Down
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@
"autoload": {
"psr-4": {
"Slides\\Saml2\\": "src/"
}
},
"files": [
"src/helpers.php"
]
},
"extra": {
"laravel": {
Expand Down
38 changes: 7 additions & 31 deletions config/saml2.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@
|
| If "useRoutes" set to true, the package defines five new routes:
|
| Method | URI | Name
| -------|--------------------------|------------------
| POST | {routesPrefix}/acs | saml.acs
| GET | {routesPrefix}/login | saml.login
| GET | {routesPrefix}/logout | saml.logout
| GET | {routesPrefix}/metadata | saml.metadata
| GET | {routesPrefix}/sls | saml.sls
| Method | URI | Name
| -------|-----------------------------------|------------------
| POST | {routesPrefix}/{idpKey}/acs | saml.acs
| GET | {routesPrefix}/{idpKey}/login | saml.login
| GET | {routesPrefix}/{idpKey}/logout | saml.logout
| GET | {routesPrefix}/{idpKey}/metadata | saml.metadata
| GET | {routesPrefix}/{idpKey}/sls | saml.sls
|
*/

Expand Down Expand Up @@ -216,18 +216,6 @@

'idp' => [

/*
|--------------------------------------------------------------------------
| Default Identity Provider settings.
|--------------------------------------------------------------------------
|
| You may define an identity provider to use setting from by default
| in case if processing IdP cannot be resolved by incoming request.
|
*/

'default' => env('SAML2_IDP_DEFAULT', 'oneLogin'),

/*
|--------------------------------------------------------------------------
| OneLogin Identity Provider.
Expand All @@ -236,18 +224,6 @@

'oneLogin' => [

/*
|--------------------------------------------------------------------------
| The URL (referrer) that sends a request to SP.
|--------------------------------------------------------------------------
|
| Uses to resolve the identity provider automatically by checking whether
| referrer URL matches this one.
|
*/

'url' => env('SAML2_IDP_ONE_LOGIN_URL'),

/*
|--------------------------------------------------------------------------
| The issuer URL.
Expand Down
2 changes: 2 additions & 0 deletions src/Facades/Auth.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
/**
* Class Saml2Auth
*
* @method static string|null getResolvedIdPKey()
*
* @package Slides\Saml2\Facades
*/
class Auth extends Facade
Expand Down
8 changes: 6 additions & 2 deletions src/Http/Controllers/Saml2Controller.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,18 +110,22 @@ public function sls()
/**
* Initiate a login request.
*
* @param Illuminate\Http\Request $request
*
* @return void
*
* @throws OneLoginError
*/
public function login()
public function login(Request $request)
{
$this->auth->login(config('saml2.loginRoute'));
$this->auth->login($request->query('returnTo', config('saml2.loginRoute')));
}

/**
* Initiate a logout request.
*
* @param Illuminate\Http\Request $request
*
* @return void
*
* @throws OneLoginError
Expand Down
10 changes: 5 additions & 5 deletions src/Http/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,27 @@
'prefix' => config('saml2.routesPrefix'),
'middleware' => config('saml2.routesMiddleware'),
], function () {
Route::get('/logout', array(
Route::get('/{idpKey}/logout', array(
'as' => 'saml.logout',
'uses' => 'Slides\Saml2\Http\Controllers\Saml2Controller@logout',
));

Route::get('/login', array(
Route::get('/{idpKey}/login', array(
'as' => 'saml.login',
'uses' => 'Slides\Saml2\Http\Controllers\Saml2Controller@login',
));

Route::get('/metadata', array(
Route::get('/{idpKey}/metadata', array(
'as' => 'saml.metadata',
'uses' => 'Slides\Saml2\Http\Controllers\Saml2Controller@metadata',
));

Route::post('/acs', array(
Route::post('/{idpKey}/acs', array(
'as' => 'saml.acs',
'uses' => 'Slides\Saml2\Http\Controllers\Saml2Controller@acs',
));

Route::get('/sls', array(
Route::get('/{idpKey}/sls', array(
'as' => 'saml.sls',
'uses' => 'Slides\Saml2\Http\Controllers\Saml2Controller@sls',
));
Expand Down
67 changes: 21 additions & 46 deletions src/IdpResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace Slides\Saml2;

use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;

/**
* Class IdpResolver
*
Expand All @@ -16,13 +19,6 @@ class IdpResolver
*/
protected $idpConfig;

/**
* The referrer URL.
*
* @var string
*/
protected $referrer;

/**
* The last resolved Identity Provider.
*
Expand All @@ -34,69 +30,48 @@ class IdpResolver
* IdpResolver constructor.
*
* @param array $idpConfig
* @param string $referrer
*/
public function __construct(array $idpConfig, $referrer)
public function __construct(array $idpConfig)
{
$this->idpConfig = $idpConfig;
$this->referrer = $referrer;
}

/**
* Resolve an Identity Provider by incoming request.
*
* @return array
* @return array|null
*/
public function resolve()
{
foreach ($this->idpConfig as $key => $config) {
if($key === 'default') {
continue;
}

if(strpos($this->referrer, $config['url']) !== false) {
$this->lastResolved = $key;
if(!$idpKey = Request::segment(2)) {
Log::debug('[saml2] IdP is not present in the URL so cannot be resolved', [
'url' => Request::fullUrl()
]);

return $config;
}
return null;
}

if(!$default = $this->retrieveDefaultIdP()) {
throw new \InvalidArgumentException('Default IdP is not defined');
if(!array_key_exists($idpKey, $this->idpConfig)) {
Log::debug('[saml2] IdP key ' . $idpKey . ' is not listed in your config', [
'idpKey' => $idpKey,
'idpKeys' => array_keys($this->idpConfig)
]);

return null;
}

$this->lastResolved = $this->defaultIdPKey();
$this->lastResolved = $idpKey;

return $default;
return $this->idpConfig[$idpKey];
}

/**
* Get the latest resolved IdP's key.
*
* @return string
*/
public function getLastResolvedKey(): string
{
return $this->lastResolved;
}

/**
* Get the default IdP config.
*
* @return array|null
*/
protected function retrieveDefaultIdP()
{
return array_get($this->idpConfig, $this->defaultIdPKey());
}

/**
* Get the default's IdP key.
*
* @return string|null
*/
protected function defaultIdPKey()
public function getLastResolvedKey()
{
return array_get($this->idpConfig, 'default');
return $this->lastResolved;
}
}
59 changes: 48 additions & 11 deletions src/ServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,19 @@ class ServiceProvider extends \Illuminate\Support\ServiceProvider
protected $defer = false;

/**
* Identity Provider resolver.
*
* @var IdpResolver
*/
protected $idpResolver;

/**
* The resolved IdP key.
*
* @var string
*/
protected $resolvedIdpKey;

/**
* Bootstrap the application events.
*
Expand Down Expand Up @@ -71,7 +80,9 @@ protected function bootPublishes()
*/
public function register()
{
$this->registerAuthenticationHandler();
if(!$this->urlMatchesNeededPrefix() || !$this->registerAuthenticationHandler()) {
return;
}

$this->app->singleton('Slides\Saml2\Auth', function ($app) {
return new \Slides\Saml2\Auth(
Expand All @@ -84,20 +95,41 @@ public function register()
/**
* Register the authentication handler.
*
* @return void
* @return bool
*/
protected function registerAuthenticationHandler()
{
$this->app->singleton('OneLogin_Saml2_Auth', function ($app) {
if(!$idpConfig = $this->resolveIdentityProvider($this->app['config']['saml2']['idp'])) {
\Illuminate\Support\Facades\Log::debug('[saml2] IdP is not resolved, skipping initialization');
return false;
}

$this->app->singleton('OneLogin_Saml2_Auth', function ($app) use ($idpConfig) {
$config = $app['config']['saml2'];

$this->setConfigDefaultValues($config);

$oneLoginConfig = $config;
$oneLoginConfig['idp'] = $this->resolveIdentityProvider($config['idp']);
$oneLoginConfig['idp'] = $idpConfig;

return new OneLoginAuth($this->normalizeConfigParameters($oneLoginConfig));
});

return true;
}

/**
* Check whether current URL is matching needed prefix.
*
* @return bool
*/
protected function urlMatchesNeededPrefix(): bool
{
return !$this->app->runningInConsole()
&& \Illuminate\Support\Str::startsWith(
$this->app['request']->path(),
ltrim($this->app['config']['saml2']['routesPrefix'], '/')
);
}

/**
Expand All @@ -108,9 +140,9 @@ protected function registerAuthenticationHandler()
protected function configDefaultValues()
{
return [
'sp.entityId' => URL::route('saml.metadata'),
'sp.assertionConsumerService.url' => URL::route('saml.acs'),
'sp.singleLogoutService.url' => URL::route('saml.sls')
'sp.entityId' => URL::route('saml.metadata', ['idpKey' => $this->resolvedIdpKey]),
'sp.assertionConsumerService.url' => URL::route('saml.acs', ['idpKey' => $this->resolvedIdpKey]),
'sp.singleLogoutService.url' => URL::route('saml.sls', ['idpKey' => $this->resolvedIdpKey])
];
}

Expand Down Expand Up @@ -175,11 +207,16 @@ protected function setDefaultValue(&$var, $default)
*
* @param array $config The IdPs config.
*
* @return array
* @return array|null
*/
protected function resolveIdentityProvider(array $config): array
protected function resolveIdentityProvider(array $config)
{
return ($this->idpResolver = new IdpResolver($config, URL::previous()))
->resolve();
$config = ($this->idpResolver = new IdpResolver($config))->resolve();

$this->resolvedIdpKey = $this->idpResolver->getLastResolvedKey();

session()->flash('saml2.idpKey', $this->resolvedIdpKey);

return $config;
}
}
Loading

0 comments on commit 011ac0d

Please sign in to comment.