Skip to content

Commit

Permalink
added social-media user-provider
Browse files Browse the repository at this point in the history
  • Loading branch information
wachterjohannes committed Jul 4, 2018
1 parent fa25734 commit 29ad156
Show file tree
Hide file tree
Showing 6 changed files with 279 additions and 1 deletion.
71 changes: 71 additions & 0 deletions Entity/UserAccessToken.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

/*
* This file is part of Sulu.
*
* (c) MASSIVE ART WebServices GmbH
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Sulu\Bundle\CommunityBundle\Entity;

use Sulu\Component\Security\Authentication\UserInterface;

class UserAccessToken
{
/**
* @var UserInterface
*/
private $user;

/**
* @var string
*/
private $service;

/**
* @var string
*/
private $identifier;

/**
* @var string
*/
private $accessToken;

public function __construct(UserInterface $user, string $service, string $identifier)
{
$this->user = $user;
$this->service = $service;
$this->identifier = $identifier;
}

public function getUser(): UserInterface
{
return $this->user;
}

public function getService(): string
{
return $this->service;
}

public function getIdentifier(): string
{
return $this->identifier;
}

public function getAccessToken(): string
{
return $this->accessToken;
}

public function setAccessToken(string $accessToken): self
{
$this->accessToken = $accessToken;

return $this;
}
}
30 changes: 30 additions & 0 deletions Entity/UserAccessTokenRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

/*
* This file is part of Sulu.
*
* (c) MASSIVE ART WebServices GmbH
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Sulu\Bundle\CommunityBundle\Entity;

use Doctrine\ORM\EntityRepository;
use Sulu\Component\Security\Authentication\UserInterface;

class UserAccessTokenRepository extends EntityRepository
{
public function create(UserInterface $user, string $service, string $identifier): UserAccessToken
{
$class = $this->getClassName();

return new $class($user, $service, $identifier);
}

public function findByIdentifier(string $service, string $identifier): ?UserAccessToken
{
return $this->findOneBy(['service' => $service, 'identifier' => $identifier]);
}
}
30 changes: 30 additions & 0 deletions Resources/config/doctrine/UserAccessToken.orm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<doctrine-mapping xmlns="http://doctrine-project.org/schemas/orm/doctrine-mapping"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://doctrine-project.org/schemas/orm/doctrine-mapping http://doctrine-project.org/schemas/orm/doctrine-mapping.xsd">
<entity name="Sulu\Bundle\CommunityBundle\Entity\UserAccessToken" table="com_user_access_tokens"
repository-class="Sulu\Bundle\CommunityBundle\Entity\UserAccessTokenRepository">
<indexes>
<index columns="identifier"/>
</indexes>

<unique-constraints>
<unique-constraint columns="service,identifier"/>
</unique-constraints>

<id name="user" type="integer" association-key="true">
<generator strategy="NONE"/>
</id>

<id name="service" type="string" length="32">
<generator strategy="NONE"/>
</id>

<field name="identifier" type="string" nullable="false" length="128"/>
<field name="accessToken" type="string" nullable="false"/>

<many-to-one field="user" target-entity="Sulu\Component\Security\Authentication\UserInterface">
<join-column name="userId" referenced-column-name="id" on-delete="CASCADE"/>
</many-to-one>
</entity>
</doctrine-mapping>
5 changes: 5 additions & 0 deletions Resources/config/services.xml
Original file line number Diff line number Diff line change
Expand Up @@ -140,5 +140,10 @@
<argument type="service" id="templating"/>
<argument type="service" id="translator"/>
</service>

<!-- social-media -->
<service id="sulu_community.social_media.oauth_provider" class="Sulu\Bundle\CommunityBundle\SocialMedia\SocialMediaUserProvider">
<argument type="service" id="doctrine"/>
</service>
</services>
</container>
140 changes: 140 additions & 0 deletions SocialMedia/SocialMediaUserProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php

/*
* This file is part of Sulu.
*
* (c) MASSIVE ART WebServices GmbH
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Sulu\Bundle\CommunityBundle\SocialMedia;

use Doctrine\Common\Persistence\ManagerRegistry;
use HWI\Bundle\OAuthBundle\Connect\AccountConnectorInterface;
use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface;
use HWI\Bundle\OAuthBundle\Security\Core\User\EntityUserProvider as BaseClass;
use Sulu\Bundle\CommunityBundle\Entity\UserAccessToken;
use Sulu\Bundle\CommunityBundle\Entity\UserAccessTokenRepository;
use Sulu\Bundle\ContactBundle\Entity\ContactInterface;
use Sulu\Bundle\ContactBundle\Entity\ContactRepositoryInterface;
use Sulu\Component\Security\Authentication\UserInterface as SuluUserInterface;
use Sulu\Component\Security\Authentication\UserRepositoryInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class SocialMediaUserProvider extends BaseClass implements AccountConnectorInterface
{
/**
* @var UserAccessTokenRepository
*/
private $userAccessTokenRepository;

/**
* @var UserRepositoryInterface
*/
private $userRepository;

/**
* @var ContactRepositoryInterface
*/
private $contactRepository;

public function __construct(
ManagerRegistry $registry,
$class = SuluUserInterface::class,
array $properties = [],
$managerName = null
) {
parent::__construct($registry, $class, $properties, $managerName);

$this->userAccessTokenRepository = $this->em->getRepository(UserAccessToken::class);
$this->userRepository = $this->em->getRepository($this->em->getClassMetadata(SuluUserInterface::class)->getName());
$this->contactRepository = $this->em->getRepository($this->em->getClassMetadata(ContactInterface::class)->getName());
}

public function connect(UserInterface $user, UserResponseInterface $response)
{
// On connect, retrieve the access token and the user id
$service = $response->getResourceOwner()->getName();
$username = $response->getUsername();

// Disconnect previously connected users
$previousAccessToken = $this->userAccessTokenRepository->findByIdentifier($service, $username);
if ($previousAccessToken) {
$this->em->remove($previousAccessToken);

// FIXME necessary?
$this->em->flush();
}

$accessToken = $this->userAccessTokenRepository->create($user, $service, $username);
$accessToken->setAccessToken($response->getAccessToken());

// FIXME necessary?
$this->em->flush();
}

public function loadUserByOAuthUserResponse(UserResponseInterface $response)
{
$service = $response->getResourceOwner()->getName();
$username = $response->getUsername();
$email = $response->getEmail() ? $response->getEmail() : $username;

$accessToken = $this->userAccessTokenRepository->findByIdentifier($service, $username);

// If the user exists
if ($accessToken) {
// set access-token and return
$accessToken->setAccessToken($response->getAccessToken());

$user = $accessToken->getUser();
$user->setEmail($email);

$contact = $user->getContact();
$contact->setFirstName($response->getFirstName());
$contact->setLastName($response->getLastName());

// FIXME necessary?
$this->em->flush();

return $accessToken->getUser();
}

// else create new user
$user = $this->userRepository->createNew();

$accessToken = $this->userAccessTokenRepository->create($user, $service, $username);
$accessToken->setAccessToken($response->getAccessToken());

$contact = $this->contactRepository->createNew();
$contact->setFirstName($response->getFirstName());
$contact->setLastName($response->getLastName());
$user->setContact($contact);

$user->setUsername($this->generateRandomUsername($username, $service));
$user->setEmail($email);
$user->setSalt(uniqid());
$user->setPassword($username);
$user->setEnabled(true);
$user->setLocale('de'); // FIXME locale

$this->em->persist($contact);
$this->em->persist($user);
$this->em->persist($accessToken);

// FIXME necessary?
$this->em->flush();

return $user;
}

private function generateRandomUsername($username, $serviceName)
{
if (!$username) {
$username = 'user' . uniqid((rand()), true) . $serviceName;
}

return $username . '_' . $serviceName;
}
}
4 changes: 3 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"symfony/routing": "^3.4",
"symfony/security": "^3.4",
"symfony/security-acl": "^2.8 || ^3.0",
"symfony/swiftmailer-bundle": "^2.6.4"
"symfony/swiftmailer-bundle": "^2.6.4",
"hwi/oauth-bundle": "^0.6.2",
"php-http/httplug-bundle": "^1.10"
},
"require-dev": {
"jackalope/jackalope-doctrine-dbal": "^1.2.5",
Expand Down

0 comments on commit 29ad156

Please sign in to comment.