24slides / laravel-saml2 Goto Github PK
View Code? Open in Web Editor NEW[Laravel 5.4+] An integration to add SSO to your service via SAML2 protocol based on OneLogin toolkit with support of multiple Identity Providers
License: MIT License
[Laravel 5.4+] An integration to add SSO to your service via SAML2 protocol based on OneLogin toolkit with support of multiple Identity Providers
License: MIT License
Is this package still being maintained? I saw it was a fork of another package and was just curious since I've started integrating with it.
Q: Should NameIDFormat
be removed from the config file?
Commit 7cdac60 introduced per-tenant nameID format, stored in DB and defaulting to persistent
The config file still has a value NameIDFormat
'sp' => [
/*
|--------------------------------------------------------------------------
| NameID format.
|--------------------------------------------------------------------------
|
| Specifies constraints on the name identifier to be used to
| represent the requested subject.
|
*/
'NameIDFormat' => 'urn:oasis:names:tc:SAML:2.0:nameid-format:persistent',
But I think that value is now ignored.
Is that correct?
If so I can open a PR to remove that from config.php
I followed the readme and get this error in my Laravel app trying to logout. I placed Saml2Auth::logout()
right after Auth::logout()
.
OneLogin\Saml2\Error
Settings file not found: /var/www/html/vendor/onelogin/php-saml/settings.php
Have you seen this before? I wasn't sure how to fix it.
Am I doing something wrong or should I be setting the tenant somehow? If so I'm not sure how to best do that if I need to be storing the tenant in a session myself or calling something in the package. It seems that the routes that are defined in the package have a route resolver that my logout route wouldn't have.
Hi. When i am trying to get messageId i have the following error
Call to undefined method Slides\Saml2\Events\SignedIn::getAuth()
Any idea?
Hi everyone,
I've followed everything as explained, but in the end I get "Signature validation failed. SAML Response rejected" back.
The login URL does work, leading me eventually to the "/acs" route, where the error is then returned.
In the config file, I find these back
'x509cert' => env('SAML2_SP_CERT_x509',''),
'privateKey' => env('SAML2_SP_CERT_PRIVATEKEY',''),
Do they serve any purpose at all? I don't see them coming back in the README.md, but I don't see them being used anywhere in the code either.
I'm following along the example with an Azure AD SAML configuration and posting here because the issue seems to be coming back as a response from Azure itself, meaning I can't start debuggin my or the library's code.
Firstly, according to the documentation, "By logging out of the global SSO Session. In this case the IdP will notify you on /saml2/{uuid}/slo
endpoint (already provided)." however an /slo
endpoint does not appear to be included in the routes specified in the packages routes file.
I notice that an /sls
endpoint is also mentioned (which does exist). Are these 2 seperate endpoints or is this just a typo.
Secondly, assuming the /sls
endpoint is correct, the behaviour of the /sls endpoint does not appear to match the actions performed upon logout by my idp (OKTA), which is making a POST request to that endpoint (as outlined here). The /sls
endpont only accepts GET requests and additionally does not appear to pass on any data related to the logout when it fires the SignedOut event, which seems to contain no methods. This data would be useful to ensuring that I am logging out the correct user from an IDP initiated logout.
It looks like i'm going to need to implement my own endpoint to handle SLO, but just wanted to check if there was something I was missing, since this is described as being implemented according to the docs.
Thanks in advance for any light you can shed on this.
I have an application using this plugin. Before the user logs in, the app saves a piece of data in a session. I think have them follow a link generated by the saml_route()
helper function. The user is redirected to the SSO, they signin, and are directed back to the ACS route. By the time the code get to the acs()
method in the src/Http/Controllers/Saml2Controller.php
controller, the existing session is cleared and a new one has started.
I traced back through the middleware and the previous session data exists as the request passes through the ResolveTenant
middleware and the ones described in the readme.md file:
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
I have followed through the stacktrace but cannot figure out what is deleting my existing session and starting a new one.
Any ideas what is causing this?
I am attempting to migrate from aacotroneo/laravel-saml2
to this package. In the old package, I used the idpName
in the URL. When I create a tenant in this new package, it seems to want me to use a UUID in the URLs. For full context, here is my route:list
output:
POST saml2/{idpName}/acs ................................ saml2_acs › Aacotroneo\Saml2 › Saml2Controller@acs
GET|HEAD saml2/{idpName}/login .......................... saml2_login › Aacotroneo\Saml2 › Saml2Controller@login
GET|HEAD saml2/{idpName}/logout ....................... saml2_logout › Aacotroneo\Saml2 › Saml2Controller@logout
GET|HEAD saml2/{idpName}/metadata ................. saml2_metadata › Aacotroneo\Saml2 › Saml2Controller@metadata
GET|HEAD saml2/{idpName}/sls ................................ saml2_sls › Aacotroneo\Saml2 › Saml2Controller@sls
POST saml2/{uuid}/acs ........................................ saml.acs › Slides\Saml2 › Saml2Controller@acs
GET|HEAD saml2/{uuid}/login .................................. saml.login › Slides\Saml2 › Saml2Controller@login
GET|HEAD saml2/{uuid}/logout ............................... saml.logout › Slides\Saml2 › Saml2Controller@logout
GET|HEAD saml2/{uuid}/metadata ......................... saml.metadata › Slides\Saml2 › Saml2Controller@metadata
GET|HEAD saml2/{uuid}/sls ........................................ saml.sls › Slides\Saml2 › Saml2Controller@sls
We use on-prem ADFS for our SSO, and I have all of the IDP/Relying Party stuff setup, and I just want to migrate over to this new (actively-supported) package. Practically speaking, I will only ever have 1 tenant. How can I keep the same URL scheme as before, when I was using the Aacotroneo package?
Thanks in advance!
Github provides a service to automatically check composer dependencies for possible security vulnerabilities in 3rd party libraries. See About managing vulnerable dependencies for more info.
It's really easy to turn on detection and notification, and optionally automatic version upgrades if you enable the 3rd option too:
https://github.com/24Slides/laravel-saml2/settings/security_analysis
(requires repo admin role)
Hi, i am facing an issue when i am trying to publish vendor. The error says:
Can't locate path: </var/www/html/vendor/24slides/laravel-saml2/src../config/saml2.php>
I am using laravel 5.5 and php 7.0. The 24slides/laravel-saml2 version that composer installed is 2.0.0.
Any ideas what is the error? I believe that the error is the src.. in the path but i can not figure out how can i fix this.
Thanks in advance!
If I have a certificate file (.crt) with a private key (.key). what is the proper openssl command to generate the x509 certificate needed for this package?
Do you have instructions to upgrade to Laravel 6? I am trying to upgrade my app to Laravel 6 and this package blocks the update.
Thanks for any guidance.
I hope this package was handle IDP also, if so can we get a documentation for how to configure that, or just add a link in for IDP, AFIK in the readme everything is about SP only, or am I the one understand it wrong
My application uses 3 different IdPs. They all need a different configuration for example in the 'security' section.
To me it looks like you are using the same config/saml2.php for all tenants and only change 4 values (entityId, singleSignOnService, singleLogoutService, x509cert) Source.
Is this correct or did I miss something?
Do you have plans to change this in the future?
Are you interested in a PR for this feature?
How would you approach this?
I am now replicating the package in production server, so config is all that's left. Followed everything based on initial setup and README, but I am still getting this error when creating the tenant:
DB table is populated, yes, but the error is there. And I keep on getting a 404 page coz the SAML2 routes are not a part of my current artisan route:list
. I would like to use the default route that are supposed to be registered automatically. What am I missing here?
Hello,
We have changed in our config file the value of 'NameIDFormat' but in the painted xml of the metadata another one continues to appear
Saml2.php
<?php
return [
/*
|--------------------------------------------------------------------------
| Use built-in routes
|--------------------------------------------------------------------------
|
| If "useRoutes" set to true, the package defines five new routes:
|
| 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
|
*/
'useRoutes' => true,
/*
|--------------------------------------------------------------------------
| Built-in routes prefix
|--------------------------------------------------------------------------
|
| Here you may define the prefix for built-in routes.
|
*/
'routesPrefix' => '/auth',
/*
|--------------------------------------------------------------------------
| Middle groups to use for the SAML routes
|--------------------------------------------------------------------------
|
| Note, Laravel 5.2 requires a group which includes StartSession
|
*/
'routesMiddleware' => ['saml'],
/*
|--------------------------------------------------------------------------
| Signature validation
|--------------------------------------------------------------------------
|
| Set to true if you want to use parameters from $_SERVER to validate the signature.
|
*/
'retrieveParametersFromServer' => false,
/*
|--------------------------------------------------------------------------
| Login redirection URL.
|--------------------------------------------------------------------------
|
| The redirection URL after successful login.
|
*/
'loginRoute' => env('SAML2_LOGIN_URL'),
/*
|--------------------------------------------------------------------------
| Logout redirection URL.
|--------------------------------------------------------------------------
|
| The redirection URL after successful logout.
|
*/
'logoutRoute' => env('SAML2_LOGOUT_URL'),
/*
|--------------------------------------------------------------------------
| Login error redirection URL.
|--------------------------------------------------------------------------
|
| The redirection URL after login failing.
|
*/
'errorRoute' => env('SAML2_ERROR_URL'),
/*
|--------------------------------------------------------------------------
| Strict mode.
|--------------------------------------------------------------------------
|
| If 'strict' is True, then the PHP Toolkit will reject unsigned
| or unencrypted messages if it expects them signed or encrypted
| Also will reject the messages if not strictly follow the SAML
| standard: Destination, NameId, Conditions... are validated too.
|
*/
'strict' => true,
/*
|--------------------------------------------------------------------------
| Debug mode.
|--------------------------------------------------------------------------
|
| When enabled, errors must be printed.
|
*/
'debug' => env('SAML2_DEBUG', env('APP_DEBUG', false)),
/*
|--------------------------------------------------------------------------
| Whether to use `X-Forwarded-*` headers to determine port/domain/protocol.
|--------------------------------------------------------------------------
|
| If 'proxyVars' is True, then the Saml lib will trust proxy headers
| e.g X-Forwarded-Proto / HTTP_X_FORWARDED_PROTO. This is useful if
| your application is running behind a load balancer which terminates SSL.
|
*/
'proxyVars' => false,
/*
|--------------------------------------------------------------------------
| Service Provider configuration.
|--------------------------------------------------------------------------
|
| General setting of the service provider.
|
*/
'sp' => [
/*
|--------------------------------------------------------------------------
| NameID format.
|--------------------------------------------------------------------------
|
| Specifies constraints on the name identifier to be used to
| represent the requested subject.
|
*/
'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress',
/*
|--------------------------------------------------------------------------
| SP Certificates.
|--------------------------------------------------------------------------
|
| Usually x509cert and privateKey of the SP are provided by files placed at
| the certs folder. But we can also provide them with the following parameters.
|
*/
'x509cert' => env('SAML2_SP_CERT_x509',''),
'privateKey' => env('SAML2_SP_CERT_PRIVATEKEY',''),
/*
|--------------------------------------------------------------------------
| Identifier (URI) of the SP entity.
|--------------------------------------------------------------------------
|
| Leave blank to use the 'saml.metadata' route.
|
*/
'entityId' => env('SAML2_SP_ENTITYID','contactcenter'),
/*
|--------------------------------------------------------------------------
| The Assertion Consumer Service (ACS) URL.
|--------------------------------------------------------------------------
|
| URL Location where the <Response> from the IdP will be returned, using HTTP-POST binding.
| Leave blank to use the 'saml.acs' route.
|
*/
'assertionConsumerService' => [
'url' => '',
],
/*
|--------------------------------------------------------------------------
| The Single Logout Service URL.
|--------------------------------------------------------------------------
|
| Specifies info about where and how the <Logout Response> message MUST be
| returned to the requester, in this case our SP.
|
| URL Location where the <Response> from the IdP will be returned, using HTTP-Redirect binding.
| Leave blank to use the 'saml.sls' route.
|
*/
'singleLogoutService' => [
'url' => ''
],
],
/*
|--------------------------------------------------------------------------
| OneLogin security settings.
|--------------------------------------------------------------------------
|
|
|
*/
'security' => [
/*
|--------------------------------------------------------------------------
| NameId encryption
|--------------------------------------------------------------------------
|
| Indicates that the nameID of the <samlp:logoutRequest> sent by this SP
| will be encrypted.
|
*/
'nameIdEncrypted' => false,
/*
|--------------------------------------------------------------------------
| AuthnRequest signage
|--------------------------------------------------------------------------
|
| Indicates whether the <samlp:AuthnRequest> messages sent by
| this SP will be signed. The Metadata of the SP will offer this info
|
*/
'authnRequestsSigned' => false,
/*
|--------------------------------------------------------------------------
| Logout request signage
|--------------------------------------------------------------------------
|
| Indicates whether the <samlp:logoutRequest> messages sent by this SP
| will be signed.
|
*/
'logoutRequestSigned' => false,
/*
|--------------------------------------------------------------------------
| Logout response signage
|--------------------------------------------------------------------------
|
| Indicates whether the <samlp:logoutResponse> messages sent by this SP
| will be signed.
|
*/
'logoutResponseSigned' => false,
/*
|--------------------------------------------------------------------------
| Whether need to sign metadata.
|--------------------------------------------------------------------------
|
| The possible values:
| - false
| - true (use certs)
| - array:
| ```
| [
| 'keyFileName' => 'metadata.key',
| 'certFileName' => 'metadata.crt'
| ]
| ```
|
*/
'signMetadata' => false,
/*
|--------------------------------------------------------------------------
| Requirement to sign messages.
|--------------------------------------------------------------------------
|
| Indicates a requirement for the <samlp:Response>, <samlp:LogoutRequest> and
| <samlp:LogoutResponse> elements received by this SP to be signed.
|
*/
'wantMessagesSigned' => false,
/*
|--------------------------------------------------------------------------
| Requirement to sign assertion elements.
|--------------------------------------------------------------------------
|
| Indicates a requirement for the <saml:Assertion> elements received by
| this SP to be signed.
|
*/
'wantAssertionsSigned' => false,
/*
|--------------------------------------------------------------------------
| Requirement to encrypt NameID.
|--------------------------------------------------------------------------
|
| Indicates a requirement for the NameID received by this SP to be encrypted.
|
*/
'wantNameIdEncrypted' => false,
/*
|--------------------------------------------------------------------------
| Authentication context.
|--------------------------------------------------------------------------
|
| Set to false and no AuthContext will be sent in the AuthNRequest,
|
| Set true or don't present this parameter and you will get an
| AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'
|
| Set an array with the possible auth context values:
| ['urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509']
|
*/
'requestedAuthnContext' => true,
],
/*
|--------------------------------------------------------------------------
| Contact information.
|--------------------------------------------------------------------------
|
| It is recommended to supply a technical and support contacts.
|
*/
'contactPerson' => [
'technical' => [
'givenName' => env('SAML2_CONTACT_TECHNICAL_NAME', 'name'),
'emailAddress' => env('SAML2_CONTACT_TECHNICAL_EMAIL', '[email protected]')
],
'support' => [
'givenName' => env('SAML2_CONTACT_SUPPORT_NAME', 'Support'),
'emailAddress' => env('SAML2_CONTACT_SUPPORT_EMAIL', '[email protected]')
],
],
/*
|--------------------------------------------------------------------------
| Organization information.
|--------------------------------------------------------------------------
|
| The info in en_US lang is recommended, add more if required.
|
*/
'organization' => [
'en-US' => [
'name' => env('SAML2_ORGANIZATION_NAME', 'Name'),
'displayname' => env('SAML2_ORGANIZATION_NAME', 'Display Name'),
'url' => env('SAML2_ORGANIZATION_URL', 'http://url')
],
],
];
http://dev.contactcenter.foticos.com/auth/UUID/metadata
This XML file does not appear to have any style information associated with it. The document tree is shown below.
<md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" validUntil="2022-06-11T13:22:50Z" cacheDuration="PT604800S" entityID="contactcenter">
<md:SPSSODescriptor AuthnRequestsSigned="false" WantAssertionsSigned="false" protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="http://domain/auth/uuid/sls"/>
<md:NameIDFormat>urn:oasis:names:tc:SAML:2.0:nameid-format:persistent</md:NameIDFormat>
<md:AssertionConsumerService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="http://domain/auth/uuid/acs" index="1"/>
</md:SPSSODescriptor>
<md:Organization>
<md:OrganizationName xml:lang="en-US">Name</md:OrganizationName>
<md:OrganizationDisplayName xml:lang="en-US">Display Name</md:OrganizationDisplayName>
<md:OrganizationURL xml:lang="en-US">http://url</md:OrganizationURL>
</md:Organization>
<md:ContactPerson contactType="technical">
<md:GivenName>name</md:GivenName>
<md:EmailAddress>[email protected]</md:EmailAddress>
</md:ContactPerson>
<md:ContactPerson contactType="support">
<md:GivenName>Support</md:GivenName>
<md:EmailAddress>[email protected]</md:EmailAddress>
</md:ContactPerson>
</md:EntityDescriptor>
Hi @brezzhnev / @dmyers !
Currently i'm migrating from the old(er) package "aacotroneo/laravel-saml2" to yours.
One thing that I about this version is that i'm in control of the SingleSignOnService URL.
"...../saml2/idp/SSOService.php"
In the older package this was written in the config.
Anything related to the IDP isn't configurable anymore.
I would like to make this dynamic, with an extra PHP function.
For example:
"...../saml2/idp/SSOService.php".myFunction();
/**
* @return string
*/
function myFunction()
{
if (isset($_GET['admin']){
$source = 'admin';
}
$source ='user';
return '?source=' . $source;
}
Previous you could do this in the config, but it looks like the "OneLoginBuilder" is already setting it (throughout my db)
$oneLoginConfig['idp'] = [
'entityId' => $this->tenant->idp_entity_id,
'singleSignOnService' => ['url' => $this->tenant->idp_login_url],
'singleLogoutService' => ['url' => $this->tenant->idp_logout_url],
'x509cert' => $this->tenant->idp_x509_cert
];
I'm looking forward to your solution, where can I overrule this "singleSignOnService url"?
Slides\Saml2\ServiceProvider.boot() calls $this->loadMigrations();
Why would it be necessary to call this every time the ServiceProvider is instantiated
Is this is not a one-time set-up step?
Its not correct:
php artisan vendor:publish --provider="Slides\Saml2\ServiceProvider
the correct is without (")
php artisan vendor:publish --provider=Slides\Saml2\ServiceProvider
Hi,
I appreciate your work on this package, it is helping me a lot during development.
Currently, I am having some issues regarding adding the certificates in production environment. In development, the only working method to me is by putting the sp.crt
and sp.key
inside vendor/onelogin/php-saml/certs
folder and it is working fine. but as per Onelogin docs:
Important In this option, the x509 certs must be stored at vendor/onelogin/php-saml/certs and settings file stored at vendor/onelogin/php-saml.
Your settings are at risk of being deleted when updating packages using composer update or similar commands. So it is highly recommended that instead of using settings files, you pass the settings as an array directly to the constructor (explained later in this document). If you do not use this approach your settings are at risk of being deleted when updating packages using composer update or similar commands.
so I can't figure out how to add sp.crt
and sp.key
per tenant in production.
As per your docs:
x509 certificate — The certificate provided by Identity Provider in base64 format
if this is the sp.crt
, what about the sp.key
? where to add it?
kindly I need your support
Hello,
I keep getting this error:
{"error":"The response was received at http://localhost/saml2/***/acs instead of https://***.com/***/acs"}
I noticed this was due to the HTTP_HOST being localhost. I noticed there is config config named baseUrl in the onelogin settings_example.php file that can override the HTTP_HOST in the url generation. Since the packages are in the /vendor folder (which is in .gitignore) if I do some changes in the files they will not be applied in the repo.
Is there a setting in the published saml config file that can change the baseUrl? How can I achieve this?
Thanks!
After user logged in, I would like to redirect to a specific page. Each user may be redirected to a different page, depending on some settings. There is a method called getIntendedUrl, which I believe is the most correct to use. however I can not identify a function where I can set this information. Does anyone know if there is a way, without having to implement the 'acs' method?
Hello,
The are some cases which don't work here:
Problem is:
Correct me if I am wrong on concept & reported problems.
In the documentation there is a comment about replay attacks:
$messageId = $event->getAuth()->getLastMessageId();
// your own code preventing reuse of a $messageId to stop replay attacks
What do we need to do here?
I found this answer an Stackoverflow, about InResponseTo
. Is there a way to get this InResponseTo
? Doesn't this require another event before the login?
I configured my IDP and followed the instructions given in the Readme section.
When I call https://url-of-my-website/saml2/{uuid}/login I see the SSO page of my IDP.
After successfully logging in I am ending up in a redirect loop:
https://my-idp-sso-provider/saml2/idp/?SAMLRequest=&RelayState=https://url-of-my-website/saml2/{uuid}/login
For each redirect I see [2022-08-09 18:06:28] local.DEBUG: [Saml2] Tenant resolved {"uuid":"uuid","id":1,"key":"sso_key"} in my laravel log.
`
Event::listen(SignedIn::class, function (SignedIn $event) {
$messageId = $event->getAuth()->getLastMessageId();
// your own code preventing reuse of a $messageId to stop replay attacks
$samlUser = $event->getSaml2User();
$userData = [
'id' => $samlUser->getUserId(),
'attributes' => $samlUser->getAttributes(),
'assertion' => $samlUser->getRawSamlAssertion()
];
// Just dump login works
//dd($userData);
$username = $userData["attributes"]["username"]; // find user by ID or attribute
$user = User::where('name',$username) -> first();
// Login a user.
Auth::loginUsingId($user->id);
});
`
From the Kernel
`
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'saml' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
],
'api' => [
// \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
];
`
From saml2.php
'routesMiddleware' => ['saml'],
I believe this is the x509certMulti
settings in OneLogin.
From their docs:
IdP with multiple certificates
In some scenarios the IdP uses different certificates for signing/encryption, or is under key rollover phase and more than one certificate is published on IdP metadata.
Currently if I'm trying to sign in a user that has no permission to the application signing in to, if got an error 500:
[2022-11-29 13:57:14] staging.ERROR: saml2.error_detail {"error":"The status code of the Response was not Success, was Responder -> urn:oasis:names:tc:SAML:2.0:status:RequestDenied"}
[2022-11-29 13:57:14] staging.ERROR: saml2.error ["invalid_response"]
[2022-11-29 13:57:14] staging.ERROR: Symfony\Component\HttpFoundation\Response::setContent(): Argument #1 ($content) must be of type ?string, Illuminate\Routing\Redirector given, called in .../vendor/laravel/framework/src/Illuminate/Http/Response.php on line 72 {"exception":"[object] (TypeError(code: 0): Symfony\\Component\\HttpFoundation\\Response::setContent(): Argument #1 ($content) must be of type ?string, Illuminate\\Routing\\Redirector given, called in .../vendor/laravel/framework/src/Illuminate/Http/Response.php on line 72 at .../vendor/symfony/http-foundation/Response.php:412)
I am handling the login of the user in an Event listener. Where can I catch the exception and handle it correctly?
Below is the error that is returned when the response from the IDP is determined to be invalid.
Symfony\Component\HttpFoundation\Response::setContent(): Argument #1 ($content) must be of type ?string, Illuminate\Routing\Redirector given, called in \vendor\laravel\framework\src\Illuminate\Http\Response.php on line 72
I came across this when I missed copying part of the IDP cert into idp_x509_cert
.
I'm not sure this can be fixed in this package as it seems to be a Laravel issue, but I thought I'd put it here in case someone could figure out something. Worst case scenario, someone else who can't properly copy/paste (like me today) can fix the issue faster.
Currently using Laravel 10.7.1 and laravel-saml2 2.2.0
Hi, there seems to be a bug in the console script for manipulating/deleting tenants.
Specifing either an ID or a UUID leads to a SQL query syntax error.
The value cannot be an integer and a string at the same time.
The backend database is PostgreSQL. Maybe other databases are more lenient with this
but Postgres unfortunately not.
j@dev:~/vgp [saml2*]$ ./artisan saml2:delete-tenant 1a86e4e9-d8d0-4411-ac66-f4743f0250c6
Illuminate\Database\QueryException
SQLSTATE[22P02]: Invalid text representation: 7 ERROR: invalid input syntax for integer: "1a86e4e9-d8d0-4411-ac66-f4743f0250c6" (SQL: select * from "saml2_tenants" where ("id" = 1a86e4e9-d8d0-4411-ac66-f4743f0250c6 or "key" = 1a86e4e9-d8d0-4411-ac66-f4743f0250c6 or "uuid" = 1a86e4e9-d8d0-4411-ac66-f4743f0250c6) and "saml2_tenants"."deleted_at" is null)
at vendor/laravel/framework/src/Illuminate/Database/Connection.php:692
688▕ // If an exception occurs when attempting to run a query, we'll format the error
689▕ // message to include the bindings with SQL, which will make this exception a
690▕ // lot more helpful to the developer instead of just the database's errors.
691▕ catch (Exception $e) {
➜ 692▕ throw new QueryException(
693▕ $query, $this->prepareBindings($bindings), $e
694▕ );
695▕ }
696▕ }
+29 vendor frames
30 artisan:37
Illuminate\Foundation\Console\Kernel::handle()
j@dev:~/vgp [saml2*]$
The problem seems to lie in this method in class Slides\Saml2\Repositories\TenantRepository:
/**
* Find a tenant by any identifier.
*
* @param int|string $key ID, key or UUID
* @param bool $withTrashed Whether need to include safely deleted records.
*
* @return Tenant[]|\Illuminate\Database\Eloquent\Collection
*/
public function findByAnyIdentifier($key, bool $withTrashed = true)
{
return $this->query($withTrashed)
->where('id', $key)
->orWhere('key', $key)
->orWhere('uuid', $key)
->get();
}
Looks like a check is missing if $key is an integer (for 'id') or a text value (for 'uuid', or 'key').
Thanks.
Hello,
I've tried these different formats:
$url = saml_url(config('app.url'), $identity->uuid, [config('app.url') . '/login-sso-redirect']);
$url = saml_url(config('app.url'), $identity->uuid, config('app.url') . '/login-sso-redirect');
$url = saml_url(config('app.url'), $identity->uuid, ['returnTo' => config('app.url') . '/login-sso-redirect']);
But the result is still the same, and without my return parameter.
https://xxx/saml2/2365c568-1d1d-410e-88cd-6b85b643da33/login?returnTo=xxx
I wonder would it be good to have another table such as saml2_users
or saml2_connections
that is used to find the User model when logging in?
Hi.
I am having a problem, when my login event is fired it creates an infinite loop as if it does not save the session or does not register the user.
` // SAML Login
Event::listen(SignedIn::class, function (SignedIn $event) {
Log::info('SignedIn');
$saml2user = $event->getSaml2User();
if ($saml2user) {
$username = $saml2user->getUserId();
$user = User::where('username', $username)->first();
if ($user) {
// \Session::push('name', 'test');
Auth::login($user);
Session::save();
}
});`
This is what my session saves.
a:6:{s:5:"saml2"; a:1:{s:6:"tenant";a:0:{}} s:6:"_flash"; a:2:{s:3:"new";a:0:{}s:3:"old";a:0:{}} s:6:"_token"; s:40:"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx s:50:"login_web_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";i:45;s:9:"_previous"; a:1:{s:3:"url";s:73:"https://group.net/images/logo/favicon.png";} s:17:"password_hash_web";s:60:"$xxxx$xxxx$xxxxxxxxxxxxxxxxxxx.xxxxxxx.xxxxx.xxxxxxxxxxxx";}
Hello.
Has anyone got this working with OneLogin? Our implementation works great with Azure AD but I've tried a variety of configurations in OneLogin and nothing seems to work. In our SamlSignInListener
I've added
if (isset($event->user)) {
Log::channel('stdout')->info(json_encode($event->user));
Log::channel('stdout')->info(json_encode($event->auth));
}
Both always return null.
I've been working to integrate this package and was thinking it would be nice if it supported like a config of mapping of urn:oid values to model attributes automatically which then can be used on the model such as this:
$attributes = $samlUser->mappedAttributes();
$laravelUser->fill($attributes);
The config could look something like this:
return [
'first_name' => [
'urn:oid:2.5.4.42',
'firstName',
],
];
And the Saml2User method:
protected function mappedAttributes(): array
{
$attributes = $this->getAttributes();
$result = collect(config('saml2.attribute_mapping')
->mapWithKeys(function ($map, $attribute) use ($attributes) {
foreach ($map as $key) {
$values = Arr::get($attributes, $key);
if (empty($values) || !is_array($values)) continue;
$value = Arr::first($values);
if (empty($value)) continue;
return [$attribute => $value];
}
return [$attribute => null];
});
}
return $result->all();
}
Not so much an issue but more of a question. I'm trying to use the Auth->isAuthenticated() function but can't for the life of me get the Auth model instantiated without jumping through a bunch of hoops trying to reverse engineer the middleware that sets the settings and everything. Has anyone done this before on this?
As the title suggests, I think it might be a good idea to change the expected env var for attaching the sp certifitcate to be SAML2_SP_CERT_X509
(The X uppercase), since the convention tends to be that these variables will be all uppercase, however are treated case sensitively.
The reason I came across this is because I am using this package with Laravel Vapor, and the interface for adding 'secrets' (which are what it uses for environment variables) only allows inputing key names in uppercase which meant I need to modify the variable in the config to account for this.
While obviously most people wouldn't come across this limitation, it also seems like using all uppercase for the default config would be a reasonable convention to follow, and would avoid this and similar issues for new users of this package.
Hi @brezzhnev
Do you have instructions to upgrade to Laravel 8? I am trying to upgrade my app to Laravel 8 and this package blocks the update.
You helped me with upgrading to L7 a while ago and I am hoping to do the same with L8.
#4
Thanks for any guidance.
Currently when actions are executed on the tenant, they are carried out on the default database.
Add new variable in the saml configuration to use a different connection driver than the "default"
For the first case, call Saml2Auth::logout(); or redirect the user to the route saml.logout which does just that. Do not close the session immediately as you need to receive a response confirmation from the IdP (redirection). That response will be handled by the library at /saml2/sls and will fire an event for you to complete the operation.
First of all, I have config'd my app based on the instructions found in the README file. Second, I am able to login just fine.
Now, I am having issues w/ the logout
process, once I hit the /saml/{UUID}/logout
route WITH or WITHOUT the returnTo
parameter set, I always end up stuck in MS Azure's logout screen. No redirect is happening at all.
If I do the same, but for the /saml/{UUID}/login
route, everything is a-okay. Why is MS Azure not redirecting back to my app after a successful logout? Does the sls
route need to be configured in MS Azure?
What am I missing? Please advise.
Hi,
I got a redirect loop on the Microsoft Login page. It keeps log in and log in and log in. The following code is my event listener.
namespace App\Listeners;
use Slides\Saml2\Events\SignedIn;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Support\Facades\Auth;
use App\Providers\RouteServiceProvider;
class Saml2SignedIn
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param SignedIn $event
* @return void
*/
public function handle(SignedIn $event)
{
// your own code preventing reuse of a $messageId to stop replay attacks
$user = $event->getSaml2User();
$userEmail = $user->getAttributes()['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress'][0];
$name = $user->getAttributes()['http://schemas.microsoft.com/identity/claims/displayname'][0];
$searchUser = \App\Models\User::where('email', $userEmail)->first();
if ($searchUser) {
Auth::login($searchUser, true);
ray('login from existing user');
ray($searchUser);
return redirect('/');
} else {
$azureUser = \App\Models\User::create([
'name' => $name,
'email' => $userEmail,
'password' => bcrypt('password')
]);
Auth::login($azureUser, true);
ray('login from new user');
return redirect(RouteServiceProvider::HOME);
}
}
}
I'm able to see the login is success by adding ray debug ray('login from existing user');
. After logged in, it keeps redirect to the same login page again.
First of all, thanks for the great package. SSO is such a confusing thing, but this package makes it much simpler.
I've been able to get IPD initiated logins working very quickly.
I'd like to ask what is the best way to add SP initiated login to the system. How do you figure out which user is linked to which tenant?
Thank you in advance
Hello, I have issue regarding the authentication, I logged in using the Event listener "UserLoggedIn". But once I get the Auth::user() in Controller, I'm getting a null value.
I also tried saving the userData in Session but once I try to obtain the value of the Session, I'm getting null. Maybe middleware issue?
I'm using Laravel 8+ and NextJS
UserLoggedIn
<?php
namespace App\Listeners;
use App\Models\User;
use Illuminate\Http\Request;
use Slides\Saml2\Events\SignedIn;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
class UserLoggedIn
{
public $request;
/**
* Create the event listener.
*
* @return void
*/
public function __construct(Request $request)
{
//
$this->request = $request;
}
/**
* Handle the event.
*
* @param Slides\Saml2\Events\SignedIn $event
* @return void
*/
public function handle(SignedIn $event)
{
$messageId = $event->auth->getLastMessageId();
// your own code preventing reuse of a $messageId to stop replay attacks
$samlUser = $event->auth->getSaml2User();
$userData = [
'id' => $samlUser->getUserId(),
'attributes' => $samlUser->getAttributes(),
'assertion' => $samlUser->getRawSamlAssertion()
];
// dd($userData);
// Login a user.
// Auth::login($user);
$searchUser = User::where('email', $userData['attributes']['email'])->first();
if ($searchUser) {
Auth::login($searchUser);
} else {
$newUser = User::create([
'name' => $userData['attributes']['first_name'][0],
'email' => $userData['attributes']['email'][0],
'role' => 'admin',
'password' => bcrypt('password')
]);
Auth::login($newUser);
}
}
}
Kernel.php
<?php
namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel
{
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array<int, class-string|string>
*/
protected $middleware = [
// \App\Http\Middleware\TrustHosts::class,
\App\Http\Middleware\TrustProxies::class,
\Illuminate\Http\Middleware\HandleCors::class,
\App\Http\Middleware\PreventRequestsDuringMaintenance::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
// \Illuminate\Session\Middleware\StartSession::class,
];
/**
* The application's route middleware groups.
*
* @var array<string, array<int, class-string|string>>
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
// \Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'api' => [
\Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
'throttle:api',
\Illuminate\Routing\Middleware\SubstituteBindings::class,
],
'saml' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
// \App\Http\Middleware\SAMLAuthenticated::class,
// \App\Listeners\UserLoggedIn::class,
// \Slides\Saml2\Events\SignedIn::class,
// \App\Listeners\UserLoggedIn::class,
],
];
/**
* The application's route middleware.
*
* These middleware may be assigned to groups or used individually.
*
* @var array<string, class-string|string>
*/
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class,
'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
'can' => \Illuminate\Auth\Middleware\Authorize::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
'signed' => \App\Http\Middleware\ValidateSignature::class,
'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
'auth.saml' => \App\Http\Middleware\SAMLAuthenticated::class,
];
}
api.php
<?php
use App\Http\Controllers\AuthController;
use App\Http\Controllers\ContactInfoController;
use App\Http\Controllers\InitiativeController;
use App\Http\Controllers\PageController;
use App\Http\Controllers\PillarController;
use App\Http\Controllers\ProgramController;
use App\Http\Controllers\SDGContributionController;
use App\Http\Controllers\SDGProgressController;
use App\Http\Controllers\SDGStrategyController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Facades\Session;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
// Route::middleware('saml')->group(function () {
Route::post('create-page', [PageController::class, 'store']);
Route::get('all-pages', [PageController::class, 'showAll']);
Route::get('single-page/{id}', [PageController::class, 'show']);
Route::post('edit-page/{id}', [PageController::class, 'update']);
Route::delete('remove-page/{id}', [PageController::class, 'destroy']);
Route::post('publish-page/{id}', [PageController::class, 'publish']);
Route::post('create-sdg-strategy', [SDGStrategyController::class, 'store']);
Route::get('all-sdg-strategies', [SDGStrategyController::class, 'showAll']);
Route::get('single-sdg-strategy/{id}', [SDGStrategyController::class, 'show']);
Route::post('edit-sdg-strategy/{id}', [SDGStrategyController::class, 'update']);
Route::delete('remove-sdg-strategy/{id}', [SDGStrategyController::class, 'destroy']);
Route::post('create-sdg-progress', [SDGProgressController::class, 'store']);
Route::get('all-sdg-progresses', [SDGProgressController::class, 'showAll']);
Route::get('single-sdg-progress/{id}', [SDGProgressController::class, 'show']);
Route::post('edit-sdg-progress/{id}', [SDGProgressController::class, 'update']);
Route::delete('remove-sdg-progress/{id}', [SDGProgressController::class, 'destroy']);
Route::post('create-pillar', [PillarController::class, 'store']);
Route::get('all-pillars', [PillarController::class, 'showAll']);
Route::get('single-pillar/{id}', [PillarController::class, 'show']);
Route::post('edit-pillar/{id}', [PillarController::class, 'update']);
Route::delete('remove-pillar/{id}', [PillarController::class, 'destroy']);
Route::post('create-initiative', [InitiativeController::class, 'store']);
Route::get('all-initiatives', [InitiativeController::class, 'showAll']);
Route::get('single-initiative/{id}', [InitiativeController::class, 'show']);
Route::post('edit-initiative/{id}', [InitiativeController::class, 'update']);
Route::delete('remove-initiative/{id}', [InitiativeController::class, 'destroy']);
Route::get('all-contact-infos', [ContactInfoController::class, 'showAll']);
Route::get('single-contact-info/{id}', [ContactInfoController::class, 'show']);
Route::post('edit-contact-info/{id}', [ContactInfoController::class, 'update']);
Route::post('create-program', [ProgramController::class, 'store']);
Route::get('all-programs', [ProgramController::class, 'showAll']);
Route::get('single-program/{id}', [ProgramController::class, 'show']);
Route::post('edit-program/{id}', [ProgramController::class, 'update']);
Route::delete('remove-program/{id}', [ProgramController::class, 'destroy']);
// Secured routes go here
Route::get('test', function(Request $request) {
Session::put('userData2', 'sample_user26');
Session::save();
});
Route::get('login', function () {
return response()->json([
'URL' => 'http://localhost:8000/saml2/51af91b9-b072-4654-9be8-9f947989a879/login',
], 200);
});
Route::redirect('logout', '/saml2/51af91b9-b072-4654-9be8-9f947989a879/logout')->name('logout');
// });
Route::middleware('auth:sanctum')->get('/user', function (Request $request) {
return $request->user();
});
auth.php
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Defaults
|--------------------------------------------------------------------------
|
| This option controls the default authentication "guard" and password
| reset options for your application. You may change these defaults
| as required, but they're a perfect start for most applications.
|
*/
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
/*
|--------------------------------------------------------------------------
| Authentication Guards
|--------------------------------------------------------------------------
|
| Next, you may define every authentication guard for your application.
| Of course, a great default configuration has been defined for you
| here which uses session storage and the Eloquent user provider.
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| Supported: "session"
|
*/
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'saml' => [
'driver' => 'session',
'provider' => 'users',
],
],
/*
|--------------------------------------------------------------------------
| User Providers
|--------------------------------------------------------------------------
|
| All authentication drivers have a user provider. This defines how the
| users are actually retrieved out of your database or other storage
| mechanisms used by this application to persist your user's data.
|
| If you have multiple user tables or models you may configure multiple
| sources which represent each model / table. These sources may then
| be assigned to any extra authentication guards you have defined.
|
| Supported: "database", "eloquent"
|
*/
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
/*
|--------------------------------------------------------------------------
| Resetting Passwords
|--------------------------------------------------------------------------
|
| You may specify multiple password reset configurations if you have more
| than one user table or model in the application and you want to have
| separate password reset settings based on the specific user types.
|
| The expire time is the number of minutes that each reset token will be
| considered valid. This security feature keeps tokens short-lived so
| they have less time to be guessed. You may change this as needed.
|
*/
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
/*
|--------------------------------------------------------------------------
| Password Confirmation Timeout
|--------------------------------------------------------------------------
|
| Here you may define the amount of seconds before a password confirmation
| times out and the user is prompted to re-enter their password via the
| confirmation screen. By default, the timeout lasts for three hours.
|
*/
'password_timeout' => 10800,
];
EventServiceProvider
<?php
namespace App\Providers;
use App\Listeners\UserLoggedIn;
use App\Models\User;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Session;
use Slides\Saml2\Events\SignedIn;
use Slides\Saml2\Events\SignedOut;
class EventServiceProvider extends ServiceProvider
{
/**
* The event to listener mappings for the application.
*
* @var array<class-string, array<int, class-string>>
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
SignedIn::class => [
UserLoggedIn::class,
],
];
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
parent::boot();
Event::listen(Slides\Saml2\Events\SignedOut::class, function (SignedOut $event) {
Auth::logout();
Session::save();
});
}
/**
* Determine if events and listeners should be automatically discovered.
*
* @return bool
*/
public function shouldDiscoverEvents()
{
return true;
}
}
.env
SANCTUM_STATEFUL_DOMAINS=web.globe-cms.test
SESSION_DOMAIN=.globe-cms.test
Hi @brezzhnev ,
Do you have instructions to upgrade to Laravel 7? I am trying to upgrade my app to Laravel 7 and this package blocks the update.
You helped me with upgrading to L6 while ago and I am hoping to do the same with L7.
Thanks for any guidance.
Hi,
the readme says under "Authentication events", that you should "add listeners on Slides\Saml2\SignedIn and Slides\Saml2\SignedOut events.", but it does not tell where (in which file) one should do that - is there any example showing exactly what to do?
kind regards,
Christoph
Hello, thank you for this package.
I have some questions about certificate expiration management.
If the IdP's certificate has expired, will it still work? (apparently the onelogin package does not handle this case)
If the IdP's certificate has changed, wouldn't it be better to to automatically update it in the database from the metadata?
what are the best practices if we change the sp certificate ? is there a way to automatically warn the idp other than the updated metadata file ?
Thanks a lot !
I'm trying to use this package alongside the multi-tenancy package https://github.com/archtechx/tenancy.
This package creates seperate databases for the tenants while using the default database as a 'central' database.
The SAML2 tables need to be added to the individual tenant DBs not this 'central' database, but because this package uses "loadMigrationsFrom" I do not have control over how these migrations are loaded and run.
The Multi tenancy package allows me to specify additional 'paths' to use for tenant migrations, so I can include the path to the laravel-saml2 migrations directly to get them to run where I need them. However they also still run on the 'central' DB.
What I am hoping is that an option can be added to this package to be able to disable the "loadMigrationsFrom" command, so that they do not need to be run automatically in situations like mine where they are being run by a different method.
Do you think this is something that could be included in this package (assuming a solution to this does not already exist)?
If so, I can make a PR for this.
Hi all.
Rather noob question, but I'm struggling to figure out how to protect some routes in by /routes/web.php file behind SAML auth.
I added the Middleware items noted in the readme.md at https://github.com/24Slides/laravel-saml2#middleware and added "->middleware('saml');" to the routes I want to ensure are behind SAML auth. When I go to those routes though in a new/incognito browser session, the view loads, where I was hoping it would redirect first through SAML.
I did add the Auth events listener from https://github.com/24Slides/laravel-saml2#authentication-events - slightly modified to get some extra attributes from the IdP - and I have the auth working OK and even have on-demand/JIT user provisioning to the Users model on appropriate accounts. This is using the redirect link method - e.g. https://my.website/saml2/UUID/login?returnTo=https://my.website/page/123 - so I am sure SAML auth itself is working OK.
Is there something simple that I'm missing here? I only have one IdP configured, so I was hoping to have a simple "->middleware('saml')" solution for my routes that would redirect any unauth'd requests to the IdP first.
Cheers!
This is more of a discussion than a bug report.
I am using sub-domains to identify my tenants, not a uuid in the path.
So, one tenant might access my app via:
tenant1.myapplication.com
To achieve this, I have set saml2.useRoutes
to false
, and removed the default UUID from the route.
Then, I had to replace the ResolveTenant
middleware, to find a tenant first from my own tenants
table, then get the saml2_tenants
via a relationship.
I also had to extend part of OneLoginBuilder
, the configDefaultValues
method, to use the correct routes, instead of this URL::route('saml.metadata', ['uuid' => $this->tenant->uuid])
.
This is needed because the current method would generate:
tenant1.myapplication.com/saml2/metadata?uuid=123e4567-e89b-12d3-a456-426614174000
The IdP doesnt like. It would be better as:
tenant1.myapplication.com/saml2/metadata
This isnt much work, but feels like I am going against the package.
Would you be open to a discussion/ a PR around having a new way to resolve tenants based on a saml_tenants.sub_domain value.
Or, ideally, would be to use it from a custom tenant model (#49)!
Right now, its quite an opinionated package, but we could make it GREAT! Im excited to hear your reply!
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.