diff --git a/.env b/.env index 48243088..f3dad674 100644 --- a/.env +++ b/.env @@ -68,6 +68,8 @@ OAUTH_BITBUCKET_CLIENT_ID= OAUTH_BITBUCKET_CLIENT_SECRET= OAUTH_BUDDY_CLIENT_ID= OAUTH_BUDDY_CLIENT_SECRET= +OAUTH_GOOGLE_CLIENT_ID= +OAUTH_GOOGLE_CLIENT_SECRET= ###< oauth ### ###> google analytics ### diff --git a/.env.docker b/.env.docker index 74b445db..05312fb5 100644 --- a/.env.docker +++ b/.env.docker @@ -72,6 +72,8 @@ OAUTH_BITBUCKET_CLIENT_ID= OAUTH_BITBUCKET_CLIENT_SECRET= OAUTH_BUDDY_CLIENT_ID= OAUTH_BUDDY_CLIENT_SECRET= +OAUTH_GOOGLE_CLIENT_ID= +OAUTH_GOOGLE_CLIENT_SECRET= ###< oauth ### ###> google analytics ### diff --git a/composer.json b/composer.json index b07cbdf6..644fc1c2 100644 --- a/composer.json +++ b/composer.json @@ -42,6 +42,7 @@ "league/flysystem-bundle": "^1.5", "league/flysystem-cached-adapter": "^1.1", "league/oauth2-github": "^3.0", + "league/oauth2-google": "^4.0", "m4tthumphrey/php-gitlab-api": "^11.0", "munusphp/munus": "^0.4.0", "nelmio/api-doc-bundle": "^4.3", diff --git a/composer.lock b/composer.lock index 48822af0..2c1a8c36 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": "e8af89e4046a341f8d96b20a5b9e749d", + "content-hash": "33c857a7e328151473b5f1510c60113d", "packages": [ { "name": "async-aws/core", @@ -4452,6 +4452,67 @@ }, "time": "2021-05-10T13:15:40+00:00" }, + { + "name": "league/oauth2-google", + "version": "4.0.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/oauth2-google.git", + "reference": "db6d8ad67cdd7d014a1e5dd5c204a319a966de86" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/oauth2-google/zipball/db6d8ad67cdd7d014a1e5dd5c204a319a966de86", + "reference": "db6d8ad67cdd7d014a1e5dd5c204a319a966de86", + "shasum": "", + "mirrors": [ + { + "url": "https://repo.repman.io/dists/%package%/%version%/%reference%.%type%", + "preferred": true + } + ] + }, + "require": { + "league/oauth2-client": "^2.0", + "php": ">=7.3" + }, + "require-dev": { + "eloquent/phony-phpunit": "^6.0 || ^7.1", + "phpunit/phpunit": "^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\OAuth2\\Client\\": "src/" + } + }, + "notification-url": "https://repo.repman.io/downloads", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Woody Gilk", + "email": "woody.gilk@gmail.com", + "homepage": "http://shadowhand.me" + } + ], + "description": "Google OAuth 2.0 Client Provider for The PHP League OAuth2-Client", + "keywords": [ + "Authentication", + "authorization", + "client", + "google", + "oauth", + "oauth2" + ], + "support": { + "issues": "https://github.com/thephpleague/oauth2-google/issues", + "source": "https://github.com/thephpleague/oauth2-google/tree/4.0.0" + }, + "time": "2021-03-04T21:12:06+00:00" + }, { "name": "m4tthumphrey/php-gitlab-api", "version": "11.6.0", @@ -11634,94 +11695,6 @@ ], "time": "2022-05-24T11:49:31+00:00" }, - { - "name": "symfony/polyfill-uuid", - "version": "v1.24.0", - "source": { - "type": "git", - "url": "https://github.com/symfony/polyfill-uuid.git", - "reference": "7529922412d23ac44413d0f308861d50cf68d3ee" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/7529922412d23ac44413d0f308861d50cf68d3ee", - "reference": "7529922412d23ac44413d0f308861d50cf68d3ee", - "shasum": "", - "mirrors": [ - { - "url": "https://repo.repman.io/dists/%package%/%version%/%reference%.%type%", - "preferred": true - } - ] - }, - "require": { - "php": ">=7.1" - }, - "provide": { - "ext-uuid": "*" - }, - "suggest": { - "ext-uuid": "For best performance" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "1.23-dev" - }, - "thanks": { - "name": "symfony/polyfill", - "url": "https://github.com/symfony/polyfill" - } - }, - "autoload": { - "files": [ - "bootstrap.php" - ], - "psr-4": { - "Symfony\\Polyfill\\Uuid\\": "" - } - }, - "notification-url": "https://repo.repman.io/downloads", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Grégoire Pineau", - "email": "lyrixx@lyrixx.info" - }, - { - "name": "Symfony Community", - "homepage": "https://symfony.com/contributors" - } - ], - "description": "Symfony polyfill for uuid functions", - "homepage": "https://symfony.com", - "keywords": [ - "compatibility", - "polyfill", - "portable", - "uuid" - ], - "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.24.0" - }, - "funding": [ - { - "url": "https://symfony.com/sponsor", - "type": "custom" - }, - { - "url": "https://github.com/fabpot", - "type": "github" - }, - { - "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", - "type": "tidelift" - } - ], - "time": "2021-10-20T20:35:02+00:00" - }, { "name": "symfony/process", "version": "v5.4.11", diff --git a/config/packages/knpu_oauth2_client.yaml b/config/packages/knpu_oauth2_client.yaml index e7e312d3..dcaf02f3 100644 --- a/config/packages/knpu_oauth2_client.yaml +++ b/config/packages/knpu_oauth2_client.yaml @@ -30,3 +30,9 @@ knpu_oauth2_client: redirect_route: register_buddy_check redirect_params: {} use_state: true + google: + type: google + client_id: '%env(OAUTH_GOOGLE_CLIENT_ID)%' + client_secret: '%env(OAUTH_GOOGLE_CLIENT_SECRET)%' + redirect_route: register_google_check + redirect_params: {} diff --git a/config/packages/security.yaml b/config/packages/security.yaml index 475967c1..e2cfc453 100644 --- a/config/packages/security.yaml +++ b/config/packages/security.yaml @@ -34,6 +34,7 @@ security: - Buddy\Repman\Security\GitLabAuthenticator - Buddy\Repman\Security\BitbucketAuthenticator - Buddy\Repman\Security\BuddyAuthenticator + - Buddy\Repman\Security\GoogleAuthenticator entry_point: Buddy\Repman\Security\LoginFormAuthenticator logout: path: app_logout diff --git a/config/routes/annotations.yaml b/config/routes/annotations.yaml index f3011950..8b9ab077 100644 --- a/config/routes/annotations.yaml +++ b/config/routes/annotations.yaml @@ -44,3 +44,7 @@ login_bitbucket_check: login_buddy_check: path: /auth/buddy/check schemes: ['%url_scheme%'] + +login_google_check: + path: /auth/google/check + schemes: ['%url_scheme%'] diff --git a/config/services.yaml b/config/services.yaml index 35b43291..ffe2e2a2 100644 --- a/config/services.yaml +++ b/config/services.yaml @@ -102,6 +102,7 @@ services: gitlab: '%env(OAUTH_GITLAB_CLIENT_ID)%' bitbucket: '%env(OAUTH_BITBUCKET_CLIENT_ID)%' buddy: '%env(OAUTH_BUDDY_CLIENT_ID)%' + google: '%env(OAUTH_GOOGLE_CLIENT_ID)%' Buddy\Repman\Service\Security\SecurityChecker\SensioLabsSecurityChecker: arguments: diff --git a/src/Controller/OAuth/GoogleController.php b/src/Controller/OAuth/GoogleController.php new file mode 100644 index 00000000..ea2575d0 --- /dev/null +++ b/src/Controller/OAuth/GoogleController.php @@ -0,0 +1,57 @@ +ensureOAuthRegistrationIsEnabled(); + + return $this->oauth->getClient('google')->redirect([ + 'openid', + 'https://www.googleapis.com/auth/userinfo.email', + 'https://www.googleapis.com/auth/userinfo.profile', + ], []); + } + + /** + * @Route("/auth/google", name="auth_google_start", methods={"GET"}) + */ + public function auth(): Response + { + return $this->oauth + ->getClient('google') + ->redirect([ + 'openid', + 'https://www.googleapis.com/auth/userinfo.email', + 'https://www.googleapis.com/auth/userinfo.profile', + ], ['redirect_uri' => $this->generateUrl('login_google_check', [], UrlGeneratorInterface::ABSOLUTE_URL)]) + ; + } + + /** + * @Route("/register/google/check", name="register_google_check", methods={"GET"}) + */ + public function registerCheck(Request $request, GoogleClient $api): Response + { + $this->ensureOAuthRegistrationIsEnabled(); + + return $this->createAndAuthenticateUser( + 'google', + fn () => $api->fetchUserFromToken($this->oauth->getClient('google')->getAccessToken()->getToken()), + $request + ); + } +} diff --git a/src/Security/GoogleAuthenticator.php b/src/Security/GoogleAuthenticator.php new file mode 100644 index 00000000..01dd8015 --- /dev/null +++ b/src/Security/GoogleAuthenticator.php @@ -0,0 +1,42 @@ +clientRegistry = $clientRegistry; + $this->googleClient = $googleClient; + $this->userProvider = $userProvider; + $this->router = $router; + } + + public function supports(Request $request): bool + { + return $request->attributes->get('_route') === 'login_google_check'; + } + + public function authenticate(Request $request): PassportInterface + { + $email = $this->googleClient->fetchUserFromToken($this->fetchAccessToken($this->clientRegistry->getClient('google'), $request->attributes->get('_route')))->getEmail(); + $user = $this->userProvider->loadUserByIdentifier($email); + + return new SelfValidatingPassport(new UserBadge($email, function () use ($user): UserInterface { + return $user; + })); + } +} diff --git a/symfony.lock b/symfony.lock index 57bfeb2c..5c725e39 100644 --- a/symfony.lock +++ b/symfony.lock @@ -281,6 +281,9 @@ "league/oauth2-github": { "version": "2.0.0" }, + "league/oauth2-google": { + "version": "4.0.0" + }, "m4tthumphrey/php-gitlab-api": { "version": "9.17.0" }, diff --git a/templates/security/login.html.twig b/templates/security/login.html.twig index b533976d..48f41183 100644 --- a/templates/security/login.html.twig +++ b/templates/security/login.html.twig @@ -45,6 +45,12 @@ Buddy {% endif %} + + {% if oauth_enabled('google') %} + + {% include 'svg/google-icon.svg' %} Google + + {% endif %}