Skip to content
This repository has been archived by the owner on Nov 18, 2018. It is now read-only.

Commit

Permalink
Merge pull request #5 from panrafal/feature/security
Browse files Browse the repository at this point in the history
Provider for SecurityServiceProvider
  • Loading branch information
FlorinPopaCodes committed Oct 14, 2013
2 parents 931f1b7 + 5abadf2 commit 01178bd
Show file tree
Hide file tree
Showing 9 changed files with 461 additions and 0 deletions.
Empty file removed README
Empty file.
75 changes: 75 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Usage

## Simple, event driven silex extension

```php
// Configure opauth
$app['opauth'] = array(
'login' => '/auth',
'callback' => '/auth/callback',
'config' => array(
'security_salt' => '...your salt...',
'Strategy' => array(
'Facebook' => array(
'app_id' => '...',
'app_secret' => '...'
),
)
)
);

// Enable extension
$app->register(new OpauthExtension());

// Listen for events
$app->dispatcher->addListener(OpauthExtension::EVENT_ERROR, function($e) {
$this->log->error('Auth error: ' . $e['message'], ['response' => $e->getSubject()]);
$e->setArgument('result', $this->redirect('/'));
});

$app->dispatcher->addListener(OpauthExtension::EVENT_SUCCESS, function($e) {
$response = $e->getSubject();

/*
find/create a user, oauth response is in $response and it's already validated!
store the user in the session
*/

$e->setArgument('result', $this->redirect('/'));
});
```

## Advanced, symfony security listener+provider

Note, that you can use it in symfony2 projects too!

To login using opauth use /login/PROVIDER, or use `opauth_default_login` route with `provider` parameter.

```php

$app->register(new OpauthSilexProvider());
$app->register(new SecurityServiceProvider(), array(
'security.firewalls' => array(
'default' => array(
'pattern' => '^/.*',
'opauth' => array(
// 'check_path' => '/login/opauth', //default
'opauth' => [
// 'path' => '/login', //default
'security_salt' => '...your salt...',
'Strategy' => [
// your opauth strategies go here
]
]
),
'anonymous' => true,
),
)
);

```

By default, users will be looked up by username "provider:uid".

You should extend your user provider to handle OPauth results correctly by implementing `OpauthUserProviderInterface`.

5 changes: 5 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
"name": "Florin Popa",
"email": "[email protected]",
"homepage": "http://florinpopa.net"
},
{
"name": "Rafal Lindemann",
"email": "[email protected]",
"homepage": "http://stamina.pl"
}
],
"autoload": {
Expand Down
83 changes: 83 additions & 0 deletions src/SilexOpauth/Security/OpauthListener.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

namespace SilexOpauth\Security;

use Opauth;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener;

/**
* @author Rafal Lindemann
* */
class OpauthListener extends AbstractAuthenticationListener
{

protected function requiresAuthentication(Request $request)
{
if ($this->httpUtils->checkRequestPath($request, 'opauth_' . ($this->providerKey) . '_login')) {
return true;
}

return parent::requiresAuthentication($request);
}


protected function attemptAuthentication(Request $request)
{

$config = array_merge(
array(
'callback_url' => $this->options['check_path'],
'callback_transport' => 'post' // Won't work with silex session
), $this->options['opauth']
);


if (parent::requiresAuthentication($request)) {
if (!isset($_POST['opauth'])) {
throw new AuthenticationException('opauth post parameter is missing');
}
// check_path
$opauth = new Opauth($config, false);

$response = unserialize(base64_decode($_POST['opauth']));

$failureReason = null;
/**
* Check if it's an error callback
*/
if (array_key_exists('error', $response)) {
throw new AuthenticationException($response['error']);
} else {
if (empty($response['auth'])
|| empty($response['timestamp'])
|| empty($response['signature'])
|| empty($response['auth']['provider'])
|| empty($response['auth']['uid'])
) {
throw new AuthenticationException('Missing key auth response components');
} elseif (
!$opauth->validate(
sha1(print_r($response['auth'], true)),
$response['timestamp'],
$response['signature'],
$failureReason
)
) {
throw new AuthenticationException($failureReason);
} else {
$token = new OpauthToken(new OpauthResult($response['auth']));
return $this->authenticationManager->authenticate($token);
}
}
} else {
// this should redirect or print, it's an opauth thing...
new Opauth($config);
// we need to exit now unfortunately...
exit();
}
}


}
51 changes: 51 additions & 0 deletions src/SilexOpauth/Security/OpauthProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

namespace SilexOpauth\Security;

use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\User\UserProviderInterface;

/**
* @author Rafal Lindemann
* */
class OpauthProvider implements AuthenticationProviderInterface
{

protected $userProvider;

public function __construct(UserProviderInterface $userProvider)
{
$this->userProvider = $userProvider;
}


public function authenticate(TokenInterface $token)
{
/* @var $token OpauthToken */
if ($this->userProvider instanceof OpauthUserProviderInterface) {
$user = $this->userProvider->loadUserByOpauthResult($token->getOpauthResult());
} else {
$username = $token->getOpauthResult()->getProvider() . ':' . $token->getOpauthResult()->getUid();
$user = $this->userProvider->loadUserByUsername($username);
}

if ($user) {
$authenticatedToken = new OpauthToken($token->getOpauthResult(), $user->getRoles());
$authenticatedToken->setUser($user);

return $authenticatedToken;
}

throw new AuthenticationException('The OPauth authentication failed.');
}


public function supports(TokenInterface $token)
{
return $token instanceof OpauthToken;
}


}
97 changes: 97 additions & 0 deletions src/SilexOpauth/Security/OpauthResult.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

namespace SilexOpauth\Security;

/**
* @author Rafal Lindemann
* */
class OpauthResult implements \Serializable
{

protected $auth;

public function __construct($auth)
{
$this->auth = $auth;
}


public function getAuth()
{
return $this->auth;
}


public function getUid()
{
return $this->auth['uid'];
}


public function getToken()
{
return $this->auth['credentials']['token'];
}


public function getExpiry()
{
return strtotime($this->auth['credentials']['expires']);
}


public function getInfo()
{
return $this->auth['info'];
}


public function getRaw()
{
return $this->auth['info'];
}


public function getProvider()
{
return $this->auth['provider'];
}


public function getName()
{
return $this->auth['info']['name'];
}


public function getEmail()
{
return $this->auth['info']['email'];
}


public function getNickname()
{
return isset($this->auth['info']['nickname']) ? $this->auth['info']['nickname'] : null;
}


public function getPicture()
{
return isset($this->auth['info']['image']) ? $this->auth['info']['image'] : null;
}


public function serialize()
{
return serialize($this->auth);
}


public function unserialize($serialized)
{
$this->auth = unserialize($serialized);
}


}
Loading

0 comments on commit 01178bd

Please sign in to comment.