diff --git a/app/Http/Controllers/SocialiteController.php b/app/Http/Controllers/SocialiteController.php index 16ad82ba..4f10bde9 100644 --- a/app/Http/Controllers/SocialiteController.php +++ b/app/Http/Controllers/SocialiteController.php @@ -24,10 +24,10 @@ public function callback(string $provider) // If a user with the provided email address already exists, register the oauth login if ($user = User::where('email', $authUser->getEmail())->first()) { - if ($user->sso_provider !== $provider) { + if ($user->sso_provider !== null && $user->sso_provider !== $provider) { abort(403, trans('auth.sso_wrong_provider', [ - 'currentProvider' => $provider, - 'userProvider' => $user->sso_provider, + 'currentProvider' => trans('auth.sso.' . $provider), + 'userProvider' => trans('auth.sso.' . $user->sso_provider), ])); } @@ -67,8 +67,12 @@ public function callback(string $provider) protected function authorizeOauthRequest(string $provider): void { - if (config('auth.oauth.enabled') !== true || !in_array($provider, config('auth.oauth.providers'))) { - abort(403, 'Login unauthorized'); + if (config('auth.sso.enabled') !== true || !in_array($provider, config('auth.sso.providers'))) { + abort(403, trans('auth.unauthorized')); + } + + if (config('services.' . $provider . '.enabled') !== true) { + abort(403, trans('auth.sso_provider_disabled')); } } } diff --git a/composer.json b/composer.json index b8c768f1..7e55cb4e 100644 --- a/composer.json +++ b/composer.json @@ -41,7 +41,7 @@ "spatie/laravel-settings": "^3.2.3", "symfony/http-client": "^6.0", "symfony/mailgun-mailer": "^6.0", - "kovah/laravel-socialite-oidc": "^0.1" + "kovah/laravel-socialite-oidc": "^0.2.0" }, "require-dev": { "barryvdh/laravel-debugbar": "^3.2", @@ -50,7 +50,7 @@ "fakerphp/faker": "^1.12", "laravel/tinker": "^2.2", "mockery/mockery": "^1.3", - "nunomaduro/collision": "^6.1", + "nunomaduro/collision": "^v7.10", "phpunit/phpunit": "^10.0", "roave/security-advisories": "dev-latest", "squizlabs/php_codesniffer": "^3.5" diff --git a/composer.lock b/composer.lock index f26e864b..2179c576 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "fabba9ddaed0892766b3f3c46a30493e", + "content-hash": "82aaed0f0c23a2de44145e73eaa9431b", "packages": [ { "name": "aws/aws-crt-php", @@ -1928,16 +1928,16 @@ }, { "name": "kovah/laravel-socialite-oidc", - "version": "v0.1", + "version": "v0.2.0", "source": { "type": "git", "url": "https://github.com/Kovah/laravel-socialite-oidc.git", - "reference": "5bb9f107ec742505d15f09fafd519b4ce2512bc6" + "reference": "aca47884e996c964a490d91a3038cde5a4965cd4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Kovah/laravel-socialite-oidc/zipball/5bb9f107ec742505d15f09fafd519b4ce2512bc6", - "reference": "5bb9f107ec742505d15f09fafd519b4ce2512bc6", + "url": "https://api.github.com/repos/Kovah/laravel-socialite-oidc/zipball/aca47884e996c964a490d91a3038cde5a4965cd4", + "reference": "aca47884e996c964a490d91a3038cde5a4965cd4", "shasum": "" }, "require": { @@ -1983,7 +1983,7 @@ ], "support": { "issues": "https://github.com/Kovah/laravel-socialite-oidc/issues", - "source": "https://github.com/Kovah/laravel-socialite-oidc/tree/v0.1" + "source": "https://github.com/Kovah/laravel-socialite-oidc/tree/v0.2.0" }, "funding": [ { @@ -1991,7 +1991,7 @@ "type": "github" } ], - "time": "2024-09-17T22:50:54+00:00" + "time": "2024-09-18T21:45:27+00:00" }, { "name": "laracasts/flash", @@ -10386,38 +10386,43 @@ }, { "name": "nunomaduro/collision", - "version": "v6.4.0", + "version": "v7.10.0", "source": { "type": "git", "url": "https://github.com/nunomaduro/collision.git", - "reference": "f05978827b9343cba381ca05b8c7deee346b6015" + "reference": "49ec67fa7b002712da8526678abd651c09f375b2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nunomaduro/collision/zipball/f05978827b9343cba381ca05b8c7deee346b6015", - "reference": "f05978827b9343cba381ca05b8c7deee346b6015", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/49ec67fa7b002712da8526678abd651c09f375b2", + "reference": "49ec67fa7b002712da8526678abd651c09f375b2", "shasum": "" }, "require": { - "filp/whoops": "^2.14.5", - "php": "^8.0.0", - "symfony/console": "^6.0.2" + "filp/whoops": "^2.15.3", + "nunomaduro/termwind": "^1.15.1", + "php": "^8.1.0", + "symfony/console": "^6.3.4" + }, + "conflict": { + "laravel/framework": ">=11.0.0" }, "require-dev": { - "brianium/paratest": "^6.4.1", - "laravel/framework": "^9.26.1", - "laravel/pint": "^1.1.1", - "nunomaduro/larastan": "^1.0.3", - "nunomaduro/mock-final-classes": "^1.1.0", - "orchestra/testbench": "^7.7", - "phpunit/phpunit": "^9.5.23", - "spatie/ignition": "^1.4.1" + "brianium/paratest": "^7.3.0", + "laravel/framework": "^10.28.0", + "laravel/pint": "^1.13.3", + "laravel/sail": "^1.25.0", + "laravel/sanctum": "^3.3.1", + "laravel/tinker": "^2.8.2", + "nunomaduro/larastan": "^2.6.4", + "orchestra/testbench-core": "^8.13.0", + "pestphp/pest": "^2.23.2", + "phpunit/phpunit": "^10.4.1", + "sebastian/environment": "^6.0.1", + "spatie/laravel-ignition": "^2.3.1" }, "type": "library", "extra": { - "branch-alias": { - "dev-develop": "6.x-dev" - }, "laravel": { "providers": [ "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" @@ -10425,6 +10430,9 @@ } }, "autoload": { + "files": [ + "./src/Adapters/Phpunit/Autoload.php" + ], "psr-4": { "NunoMaduro\\Collision\\": "src/" } @@ -10470,7 +10478,7 @@ "type": "patreon" } ], - "time": "2023-01-03T12:54:54+00:00" + "time": "2023-10-11T15:45:01+00:00" }, { "name": "phar-io/manifest", @@ -11097,12 +11105,12 @@ "source": { "type": "git", "url": "https://github.com/Roave/SecurityAdvisories.git", - "reference": "39a2e3360d55163461cbb72e5d7c872b6c8b11a4" + "reference": "a7b092bec53b91832e9c5c389ce966b50a8d6e8b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/39a2e3360d55163461cbb72e5d7c872b6c8b11a4", - "reference": "39a2e3360d55163461cbb72e5d7c872b6c8b11a4", + "url": "https://api.github.com/repos/Roave/SecurityAdvisories/zipball/a7b092bec53b91832e9c5c389ce966b50a8d6e8b", + "reference": "a7b092bec53b91832e9c5c389ce966b50a8d6e8b", "shasum": "" }, "conflict": { @@ -11215,7 +11223,7 @@ "cuyz/valinor": "<0.12", "czim/file-handling": "<1.5|>=2,<2.3", "czproject/git-php": "<4.0.3", - "damienharper/auditor-bundle": "<6", + "damienharper/auditor-bundle": "<5.2.6", "dapphp/securimage": "<3.6.6", "darylldoyle/safe-svg": "<1.9.10", "datadog/dd-trace": ">=0.30,<0.30.2", @@ -11445,7 +11453,7 @@ "mantisbt/mantisbt": "<2.26.2", "marcwillmann/turn": "<0.3.3", "matyhtf/framework": "<3.0.6", - "mautic/core": "<4.4.12|>=5.0.0.0-alpha,<5.0.4", + "mautic/core": "<4.4.13|>=5.0.0.0-alpha,<5.1.1", "mautic/core-lib": ">=1.1.3,<4.4.13|>=5.0.0.0-alpha,<5.1.1", "mdanter/ecc": "<2", "mediawiki/core": "<1.36.2", @@ -11914,7 +11922,7 @@ "type": "tidelift" } ], - "time": "2024-09-18T18:05:47+00:00" + "time": "2024-09-18T21:04:55+00:00" }, { "name": "sebastian/cli-parser", diff --git a/config/auth.php b/config/auth.php index c2801be3..898de771 100644 --- a/config/auth.php +++ b/config/auth.php @@ -20,12 +20,12 @@ /* |-------------------------------------------------------------------------- - | OAuth Settings + | Single Sign On Settings |-------------------------------------------------------------------------- */ - 'oauth' => [ - 'enabled' => env('OAUTH_ENABLED', false), + 'sso' => [ + 'enabled' => env('SSO_ENABLED', false), 'regular_login_disabled' => env('REGULAR_LOGIN_DISABLED', false), 'providers' => [ 'auth0', diff --git a/config/services.php b/config/services.php index 6e255652..6f4d8dde 100644 --- a/config/services.php +++ b/config/services.php @@ -34,104 +34,104 @@ // OAuth and SSO 'auth0' => [ - 'enabled' => env('OAUTH_AUTH0_ENABLED', false), - 'base_url' => env('OAUTH_AUTH0_BASE_URL'), - 'client_id' => env('OAUTH_AUTH0_CLIENT_ID'), - 'client_secret' => env('OAUTH_AUTH0_CLIENT_SECRET'), - 'redirect' => '/auth/oauth/auth0/callback', + 'enabled' => env('SSO_AUTH0_ENABLED', false), + 'base_url' => env('SSO_AUTH0_BASE_URL'), + 'client_id' => env('SSO_AUTH0_CLIENT_ID'), + 'client_secret' => env('SSO_AUTH0_CLIENT_SECRET'), + 'redirect' => '/auth/sso/auth0/callback', ], 'authentik' => [ - 'enabled' => env('OAUTH_AUTHENTIK_ENABLED', false), - 'base_url' => env('OAUTH_AUTHENTIK_BASE_URL'), - 'client_id' => env('OAUTH_AUTHENTIK_CLIENT_ID'), - 'client_secret' => env('OAUTH_AUTHENTIK_CLIENT_SECRET'), - 'redirect' => '/auth/oauth/authentik/callback', + 'enabled' => env('SSO_AUTHENTIK_ENABLED', false), + 'base_url' => env('SSO_AUTHENTIK_BASE_URL'), + 'client_id' => env('SSO_AUTHENTIK_CLIENT_ID'), + 'client_secret' => env('SSO_AUTHENTIK_CLIENT_SECRET'), + 'redirect' => '/auth/sso/authentik/callback', ], 'azure' => [ - 'enabled' => env('OAUTH_AZURE_ENABLED', false), - 'client_id' => env('OAUTH_AZURE_CLIENT_ID'), - 'client_secret' => env('OAUTH_AZURE_CLIENT_SECRET'), - 'tenant' => env('OAUTH_AZURE_TENANT_ID'), + 'enabled' => env('SSO_AZURE_ENABLED', false), + 'client_id' => env('SSO_AZURE_CLIENT_ID'), + 'client_secret' => env('SSO_AZURE_CLIENT_SECRET'), + 'tenant' => env('SSO_AZURE_TENANT_ID'), 'proxy' => env('PROXY'), - 'redirect' => '/auth/oauth/azure/callback', + 'redirect' => '/auth/sso/azure/callback', ], 'cognito' => [ - 'enabled' => env('OAUTH_COGNITO_ENABLED', false), - 'host' => env('OAUTH_COGNITO_HOST'), - 'client_id' => env('OAUTH_COGNITO_CLIENT_ID'), - 'client_secret' => env('OAUTH_COGNITO_CLIENT_SECRET'), - 'redirect' => env('OAUTH_COGNITO_CALLBACK_URL'), - 'scope' => explode(',', env('OAUTH_COGNITO_LOGIN_SCOPE', '')), - 'logout_uri' => env('OAUTH_COGNITO_SIGN_OUT_URL'), + 'enabled' => env('SSO_COGNITO_ENABLED', false), + 'host' => env('SSO_COGNITO_HOST'), + 'client_id' => env('SSO_COGNITO_CLIENT_ID'), + 'client_secret' => env('SSO_COGNITO_CLIENT_SECRET'), + 'redirect' => env('SSO_COGNITO_CALLBACK_URL'), + 'scope' => explode(',', env('SSO_COGNITO_LOGIN_SCOPE', '')), + 'logout_uri' => env('SSO_COGNITO_SIGN_OUT_URL'), ], 'fusionauth' => [ - 'enabled' => env('OAUTH_FUSIONAUTH_ENABLED', false), - 'base_url' => env('OAUTH_FUSIONAUTH_BASE_URL'), - 'client_id' => env('OAUTH_FUSIONAUTH_CLIENT_ID'), - 'client_secret' => env('OAUTH_FUSIONAUTH_CLIENT_SECRET'), - 'redirect' => '/auth/oauth/fusionauth/callback', + 'enabled' => env('SSO_FUSIONAUTH_ENABLED', false), + 'base_url' => env('SSO_FUSIONAUTH_BASE_URL'), + 'client_id' => env('SSO_FUSIONAUTH_CLIENT_ID'), + 'client_secret' => env('SSO_FUSIONAUTH_CLIENT_SECRET'), + 'redirect' => '/auth/sso/fusionauth/callback', ], 'google' => [ - 'enabled' => env('OAUTH_GOOGLE_ENABLED', false), - 'client_id' => env('OAUTH_GOOGLE_CLIENT_ID'), - 'client_secret' => env('OAUTH_GOOGLE_CLIENT_SECRET'), - 'redirect' => '/auth/oauth/{provider}/callback', + 'enabled' => env('SSO_GOOGLE_ENABLED', false), + 'client_id' => env('SSO_GOOGLE_CLIENT_ID'), + 'client_secret' => env('SSO_GOOGLE_CLIENT_SECRET'), + 'redirect' => '/auth/sso/{provider}/callback', ], 'github' => [ - 'enabled' => env('OAUTH_GITHUB_ENABLED', false), - 'client_id' => env('OAUTH_GITHUB_CLIENT_ID'), - 'client_secret' => env('OAUTH_GITHUB_CLIENT_SECRET'), - 'redirect' => '/auth/oauth/github/callback', + 'enabled' => env('SSO_GITHUB_ENABLED', false), + 'client_id' => env('SSO_GITHUB_CLIENT_ID'), + 'client_secret' => env('SSO_GITHUB_CLIENT_SECRET'), + 'redirect' => '/auth/sso/github/callback', ], 'gitlab' => [ - 'enabled' => env('OAUTH_GITLAB_ENABLED', false), - 'host' => env('OAUTH_GITLAB_HOST'), - 'client_id' => env('OAUTH_GITLAB_CLIENT_ID'), - 'client_secret' => env('OAUTH_GITLAB_CLIENT_SECRET'), - 'redirect' => '/auth/oauth/gitlab/callback', + 'enabled' => env('SSO_GITLAB_ENABLED', false), + 'host' => env('SSO_GITLAB_HOST'), + 'client_id' => env('SSO_GITLAB_CLIENT_ID'), + 'client_secret' => env('SSO_GITLAB_CLIENT_SECRET'), + 'redirect' => '/auth/sso/gitlab/callback', ], 'keycloak' => [ - 'enabled' => env('OAUTH_KEYCLOAK_ENABLED', false), - 'client_id' => env('OAUTH_KEYCLOAK_CLIENT_ID'), - 'client_secret' => env('OAUTH_KEYCLOAK_CLIENT_SECRET'), - 'realms' => env('OAUTH_KEYCLOAK_REALM'), - 'redirect' => '/auth/oauth/keycloak/callback', + 'enabled' => env('SSO_KEYCLOAK_ENABLED', false), + 'client_id' => env('SSO_KEYCLOAK_CLIENT_ID'), + 'client_secret' => env('SSO_KEYCLOAK_CLIENT_SECRET'), + 'realms' => env('SSO_KEYCLOAK_REALM'), + 'redirect' => '/auth/sso/keycloak/callback', ], 'oidc' => [ - 'enabled' => env('OAUTH_OIDC_ENABLED', false), - 'base_url' => env('OAUTH_OIDC_BASE_URL'), - 'client_id' => env('OAUTH_OIDC_CLIENT_ID'), - 'client_secret' => env('OAUTH_OIDC_CLIENT_SECRET'), - 'scopes' => env('OAUTH_OIDC_SCOPES'), - 'redirect' => '/auth/oauth/oidc/callback', + 'enabled' => env('SSO_OIDC_ENABLED', false), + 'base_url' => env('SSO_OIDC_BASE_URL'), + 'client_id' => env('SSO_OIDC_CLIENT_ID'), + 'client_secret' => env('SSO_OIDC_CLIENT_SECRET'), + 'scopes' => env('SSO_OIDC_SCOPES'), + 'redirect' => '/auth/sso/oidc/callback', ], 'okta' => [ - 'enabled' => env('OAUTH_OKTA_ENABLED', false), - 'base_url' => env('OAUTH_OKTA_BASE_URL'), - 'client_id' => env('OAUTH_OKTA_CLIENT_ID'), - 'client_secret' => env('OAUTH_OKTA_CLIENT_SECRET'), - 'redirect' => '/auth/oauth/okta/callback', + 'enabled' => env('SSO_OKTA_ENABLED', false), + 'base_url' => env('SSO_OKTA_BASE_URL'), + 'client_id' => env('SSO_OKTA_CLIENT_ID'), + 'client_secret' => env('SSO_OKTA_CLIENT_SECRET'), + 'redirect' => '/auth/sso/okta/callback', ], 'zitadel' => [ - 'enabled' => env('OAUTH_ZITADEL_ENABLED', false), - 'client_id' => env('OAUTH_ZITADEL_CLIENT_ID'), - 'client_secret' => env('OAUTH_ZITADEL_CLIENT_SECRET'), - 'base_url' => env('OAUTH_ZITADEL_BASE_URL'), - 'organization_id' => env('OAUTH_ZITADEL_ORGANIZATION_ID'), - 'project_id' => env('OAUTH_ZITADEL_PROJECT_ID'), - 'post_logout_redirect_uri' => env('OAUTH_ZITADEL_POST_LOGOUT_REDIRECT_URI', '/'), - 'redirect' => '/auth/oauth/zitadel/callback', + 'enabled' => env('SSO_ZITADEL_ENABLED', false), + 'client_id' => env('SSO_ZITADEL_CLIENT_ID'), + 'client_secret' => env('SSO_ZITADEL_CLIENT_SECRET'), + 'base_url' => env('SSO_ZITADEL_BASE_URL'), + 'organization_id' => env('SSO_ZITADEL_ORGANIZATION_ID'), + 'project_id' => env('SSO_ZITADEL_PROJECT_ID'), + 'post_logout_redirect_uri' => env('SSO_ZITADEL_POST_LOGOUT_REDIRECT_URI', '/'), + 'redirect' => '/auth/sso/zitadel/callback', ], ]; diff --git a/lang/en_US/auth.php b/lang/en_US/auth.php index 37596a9a..95c5dc94 100644 --- a/lang/en_US/auth.php +++ b/lang/en_US/auth.php @@ -18,6 +18,7 @@ 'failed' => 'These credentials do not match our records.', 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', + 'unauthorized' => 'Login unauthorized. Please contact your administrator.', 'confirm_title' => 'Confirmation required', 'confirm' => 'Please confirm this action using your current password.', @@ -51,6 +52,7 @@ 'api_tokens.revoke_confirm' => 'Do you really want to revoke this token? This step cannot be undone and the token cannot be recovered.', 'api_tokens.revoke_successful' => 'The token was revoked successfully.', + 'sso_provider_disabled' => 'The selected SSO provider is not available. Please choose another one.', 'sso_wrong_provider' => 'Unable to login with :currentProvider. Please use :userProvider to login, or contact your administrator for help.', 'sso' => [ diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php index 18c7f60c..c3f0a46e 100644 --- a/resources/views/auth/login.blade.php +++ b/resources/views/auth/login.blade.php @@ -8,10 +8,10 @@