Last active
March 20, 2019 22:00
-
-
Save cursedcoder/7725072df443d4f65ad9 to your computer and use it in GitHub Desktop.
HWIOAuth with FOSUserBundle intergration + phpspec coverage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fos_user: | |
db_driver: orm | |
firewall_name: main | |
user_class: App\Entity\User | |
service: | |
user_manager: app.user_manager | |
hwi_oauth: | |
firewall_name: main | |
fosub: | |
username_iterations: 30 | |
properties: ~ | |
resource_owners: | |
facebook: | |
type: facebook | |
client_id: %oauth_facebook_key% | |
client_secret: %oauth_facebook_secret% | |
options: | |
display: popup #dialog is optimized for popup window | |
google: | |
type: google | |
client_id: %oauth_google_key% | |
client_secret: %oauth_google_secret% | |
scope: "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile" | |
twitter: | |
type: twitter | |
client_id: %oauth_twitter_key% | |
client_secret: %oauth_twitter_secret% | |
vkontakte: | |
type: vkontakte | |
client_id: %oauth_vkontakte_key% | |
client_secret: %oauth_vkontakte_secret% |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Entity; | |
use Doctrine\ORM\Mapping as ORM; | |
/** | |
* @ORM\Entity | |
*/ | |
class OAuthIdentity | |
{ | |
/** | |
* @ORM\Id | |
* @ORM\Column(type="integer") | |
* @ORM\GeneratedValue(strategy="AUTO") | |
*/ | |
private $id; | |
/** | |
* @ORM\OneToOne(targetEntity="User", inversedBy="oAuthIdentity") | |
*/ | |
private $user; | |
/** | |
* @ORM\Column(nullable=true) | |
*/ | |
private $facebookId; | |
/** | |
* @ORM\Column(nullable=true) | |
*/ | |
private $facebookToken; | |
/** | |
* @ORM\Column(nullable=true) | |
*/ | |
private $googleId; | |
/** | |
* @ORM\Column(nullable=true) | |
*/ | |
private $googleToken; | |
/** | |
* @ORM\Column(nullable=true) | |
*/ | |
private $twitterId; | |
/** | |
* @ORM\Column(nullable=true) | |
*/ | |
private $twitterToken; | |
/** | |
* @ORM\Column(nullable=true) | |
*/ | |
private $vkontakteId; | |
/** | |
* @ORM\Column(nullable=true) | |
*/ | |
private $vkontakteToken; | |
public function __construct(User $user) | |
{ | |
$this->user = $user; | |
} | |
public function getId() | |
{ | |
return $this->id; | |
} | |
public function getUser() | |
{ | |
return $this->user; | |
} | |
public function setFacebookToken($facebookToken) | |
{ | |
$this->facebookToken = $facebookToken; | |
} | |
public function getFacebookToken() | |
{ | |
return $this->facebookToken; | |
} | |
public function setFacebookId($facebookId) | |
{ | |
$this->facebookId = $facebookId; | |
} | |
public function getFacebookId() | |
{ | |
return $this->facebookId; | |
} | |
public function setGoogleToken($googleToken) | |
{ | |
$this->googleToken = $googleToken; | |
} | |
public function getGoogleToken() | |
{ | |
return $this->googleToken; | |
} | |
public function setGoogleId($googleId) | |
{ | |
$this->googleId = $googleId; | |
} | |
public function getGoogleId() | |
{ | |
return $this->googleId; | |
} | |
public function setTwitterToken($twitterToken) | |
{ | |
$this->twitterToken = $twitterToken; | |
} | |
public function getTwitterToken() | |
{ | |
return $this->twitterToken; | |
} | |
public function setTwitterId($twitterId) | |
{ | |
$this->twitterId = $twitterId; | |
} | |
public function getTwitterId() | |
{ | |
return $this->twitterId; | |
} | |
public function setVkontakteToken($vkontakteToken) | |
{ | |
$this->vkontakteToken = $vkontakteToken; | |
} | |
public function getVkontakteToken() | |
{ | |
return $this->vkontakteToken; | |
} | |
public function setVkontakteId($vkontakteId) | |
{ | |
$this->vkontakteId = $vkontakteId; | |
} | |
public function getVkontakteId() | |
{ | |
return $this->vkontakteId; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\User; | |
use FOS\UserBundle\Doctrine\UserManager as BaseManager; | |
class UserManager extends BaseManager | |
{ | |
public function findUserByOAuthService($service, $id) | |
{ | |
$repository = $this->objectManager->getRepository('App:OAuthIdentity'); | |
if ($identity = $repository->findOneBy([$service.'Id' => $id])) { | |
return $identity->getUser(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\User; | |
use App\Entity\User; | |
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface; | |
use HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider; | |
use Symfony\Component\Security\Core\User\UserInterface; | |
class OAuthProvider extends FOSUBUserProvider | |
{ | |
/** | |
* @var \Symfony\Component\PropertyAccess\PropertyAccessor | |
*/ | |
public $propertyAccessor; | |
public function connect(UserInterface $user, UserResponseInterface $response) | |
{ | |
$username = $response->getUsername(); | |
$token = $response->getAccessToken(); | |
$service = $response->getResourceOwner()->getName(); | |
if (null !== $previousUser = $this->userManager->findUserByOAuthService($service, $username)) { | |
$this->assignServiceToUser($previousUser, $service); | |
$this->userManager->updateUser($previousUser); | |
} | |
$this->assignServiceToUser($user, $service, $username, $token); | |
$this->userManager->updateUser($user); | |
} | |
public function loadUserByOAuthUserResponse(UserResponseInterface $response) | |
{ | |
$username = $response->getUsername(); | |
$token = $response->getAccessToken(); | |
$service = $response->getResourceOwner()->getName(); | |
if ($user = $this->userManager->findUserByOAuthService($service, $username)) { | |
$this->assignServiceToUser($user, $service, $username, $token); | |
} else { | |
$user = $this->userManager->createUser(); | |
$user->setUsername($username); | |
if ($response->getEmail()) { | |
$user->setEmail($response->getEmail()); | |
} else { | |
$user->setEmail($username.'@domain.com'); | |
} | |
// !!! CUSTOMIZE THAT !!! \\ | |
$user->setPlainPassword($username); | |
$user->setEnabled(true); | |
$user->addRole('ROLE_OAUTH_USER'); | |
$this->assignServiceToUser($user, $service, $username, $token); | |
$this->userManager->updateUser($user); | |
} | |
return $user; | |
} | |
private function assignServiceToUser(User $user, $service, $id = null, $token = null) | |
{ | |
if ($user->isOAuthConnected()) { | |
$identity = $user->getOAuthIdentity(); | |
} else { | |
$identity = $user->initializeOAuth(); | |
} | |
$this->propertyAccessor->setValue($identity, $service.'Id', $id); | |
$this->propertyAccessor->setValue($identity, $service.'Token', $token); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
fos_user_security: | |
resource: "@FOSUserBundle/Resources/config/routing/security.xml" | |
fos_user_register: | |
resource: "@FOSUserBundle/Resources/config/routing/registration.xml" | |
prefix: /register | |
hwi_oauth_redirect: | |
resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml" | |
prefix: /connect | |
facebook_login: | |
pattern: /login/check-facebook | |
google_login: | |
pattern: /login/check-google | |
twitter_login: | |
pattern: /login/check-twitter | |
vkontakte_login: | |
pattern: /login/check-vkontakte |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
security: | |
encoders: | |
FOS\UserBundle\Model\UserInterface: sha512 | |
role_hierarchy: | |
ROLE_OAUTH_USER: ROLE_USER | |
ROLE_ORG: ROLE_USER | |
ROLE_ADMIN: ROLE_USER | |
ROLE_SUPER_ADMIN: ROLE_ADMIN | |
providers: | |
fos_userbundle: | |
id: fos_user.user_provider.username_email | |
firewalls: | |
dev: | |
pattern: ^/(_(profiler|wdt)|css|images|js)/ | |
security: false | |
main: | |
pattern: ^/ | |
form_login: | |
provider: fos_userbundle | |
csrf_provider: form.csrf_provider | |
oauth: | |
resource_owners: | |
facebook: /login/check-facebook | |
google: /login/check-google | |
twitter: /login/check-twitter | |
vkontakte: /login/check-vkontakte | |
login_path: /login | |
failure_path: /login | |
oauth_user_provider: | |
service: app.oauth_user_provider | |
logout: true | |
anonymous: true | |
access_control: | |
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY } | |
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } | |
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY } | |
- { path: ^/admin/, role: ROLE_ADMIN } |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
parameters: | |
app.oauth_user_provider.class: App\User\OAuthProvider | |
app.user_manager.class: App\User\UserManager | |
services: | |
app.oauth_user_provider: | |
class: %app.oauth_user_provider.class% | |
arguments: [@app.user_manager, []] | |
properties: | |
propertyAccessor: @property_accessor | |
app.user_manager: | |
class: %app.user_manager.class% | |
arguments: | |
- @security.encoder_factory | |
- @fos_user.util.username_canonicalizer | |
- @fos_user.util.email_canonicalizer | |
- @doctrine.orm.entity_manager | |
- %fos_user.model.user.class% |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace spec\App\User; | |
use App\Entity\OAuthIdentity; | |
use App\Entity\User; | |
use App\User\UserManager; | |
use HWI\Bundle\OAuthBundle\OAuth\ResourceOwnerInterface; | |
use HWI\Bundle\OAuthBundle\Tests\Fixtures\CustomUserResponse; | |
use PhpSpec\ObjectBehavior; | |
use Prophecy\Argument; | |
use Symfony\Component\PropertyAccess\PropertyAccessor; | |
class OAuthProviderSpec extends ObjectBehavior | |
{ | |
public function let(UserManager $um) | |
{ | |
$this->beConstructedWith($um, []); | |
} | |
public function it_connects_user_form_oauth_response | |
( | |
UserManager $um, | |
User $user, | |
CustomUserResponse $response, | |
ResourceOwnerInterface $owner, | |
OAuthIdentity $identity, | |
PropertyAccessor $pa | |
) | |
{ | |
$this->propertyAccessor = $pa; | |
$service = 'vkontakte'; | |
$username = 111; | |
$token = 'abasdasdasdcv323'; | |
$owner->getName()->willReturn($service); | |
$response->getUsername()->willReturn($username); | |
$response->getAccessToken()->willReturn($token); | |
$response->getResourceOwner()->willReturn($owner); | |
$um->findUserByOAuthService($service, $username)->willReturn(null); | |
$um->updateUser($user)->shouldBeCalled(); | |
$user->isOAuthConnected()->willReturn(true); | |
$user->getOAuthIdentity()->willReturn($identity); | |
$pa->setValue($identity, $service.'Id', $username)->shouldBeCalled(); | |
$pa->setValue($identity, $service.'Token', $token)->shouldBeCalled(); | |
$this->connect($user, $response); | |
} | |
public function it_disconnects_previous_user_and_connects_new | |
( | |
UserManager $um, | |
User $prevUser, | |
User $newUser, | |
CustomUserResponse $response, | |
ResourceOwnerInterface $owner, | |
OAuthIdentity $prevIdentity, | |
OAuthIdentity $newIdentity, | |
PropertyAccessor $pa | |
) | |
{ | |
$this->propertyAccessor = $pa; | |
$service = 'vkontakte'; | |
$username = 111; | |
$token = 'abasdasdasdcv323'; | |
$owner->getName()->willReturn($service); | |
$response->getUsername()->willReturn($username); | |
$response->getAccessToken()->willReturn($token); | |
$response->getResourceOwner()->willReturn($owner); | |
$prevUser->isOAuthConnected()->willReturn(true); | |
$prevUser->getOAuthIdentity()->willReturn($prevIdentity); | |
$newUser->isOAuthConnected()->willReturn(true); | |
$newUser->getOAuthIdentity()->willReturn($newIdentity); | |
$um->findUserByOAuthService($service, $username)->willReturn($prevUser); | |
$pa->setValue($prevIdentity, $service.'Id', null)->shouldBeCalled(); | |
$pa->setValue($prevIdentity, $service.'Token', null)->shouldBeCalled(); | |
$um->updateUser($prevUser)->shouldBeCalled(); | |
$pa->setValue($newIdentity, $service.'Id', $username)->shouldBeCalled(); | |
$pa->setValue($newIdentity, $service.'Token', $token)->shouldBeCalled(); | |
$um->updateUser($newUser)->shouldBeCalled(); | |
$this->connect($newUser, $response); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Entity; | |
use Doctrine\ORM\Mapping as ORM; | |
use FOS\UserBundle\Model\User as BaseUser; | |
/** | |
* @ORM\Entity | |
*/ | |
class User extends BaseUser | |
{ | |
/** | |
* @ORM\Id | |
* @ORM\Column(type="integer") | |
* @ORM\GeneratedValue(strategy="AUTO") | |
*/ | |
protected $id; | |
/** | |
* @ORM\OneToOne(targetEntity="OAuthIdentity", cascade={"all"}, mappedBy="user") | |
*/ | |
private $oAuthIdentity; | |
public function isOAuthConnected() | |
{ | |
return is_object($this->oAuthIdentity); | |
} | |
public function initializeOAuth() | |
{ | |
$this->oAuthIdentity = new OAuthIdentity($this); | |
return $this->oAuthIdentity; | |
} | |
public function getOAuthIdentity() | |
{ | |
return $this->oAuthIdentity; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment