Skip to content

Instantly share code, notes, and snippets.

@aertmann
Created June 30, 2015 10:49
Show Gist options
  • Select an option

  • Save aertmann/85c74cc608f7f41daf77 to your computer and use it in GitHub Desktop.

Select an option

Save aertmann/85c74cc608f7f41daf77 to your computer and use it in GitHub Desktop.
Token based authentication for Flow 3.x
<?php
namespace Acme\Demo\Controller;
/* *
* This script belongs to the TYPO3 Flow package "Acme.Demo". *
* *
* */
use TYPO3\Flow\Annotations as Flow;
use Acme\Demo\Domain\Model\Token;
use TYPO3\Flow\Error\Message;
use TYPO3\Flow\Mvc\Controller\ActionController;
/**
* Class Controller
*
* @package Acme\Demo\Controller
*/
class Controller extends ActionController {
/**
* @Flow\Inject
* @var \Acme\Demo\Service\TokenService
*/
protected $tokenService;
/**
* @var \Acme\Demo\Log\LoggerInterface
* @Flow\Inject
*/
protected $logger;
/**
* @var Token
*/
protected $token;
/**
* @return void
*/
protected function initializeAction() {
parent::initializeAction();
$this->token = $this->tokenService->getToken();
}
/**
* @return void
* @throws \Exception
*/
public function tokenAction() {
$forwardAction = 'noAccess';
if (is_null($this->token)) {
$exception = new \Exception('Token not found');
$this->addFlashMessage('Invalid token', '', Message::SEVERITY_ERROR);
$this->logger->logException($exception, array($this->token));
throw new $exception;
} elseif (!is_null($this->token->getAccess())) {
$exception = new \Exception('Token does not grant any access');
$this->logger->logException($exception);
throw new $exception;
} else {
$forwardAction = $this->token->getAccess();
}
$this->redirect($forwardAction);
}
/**
* @return void
*/
public function indexAction() {
}
/**
* @return void
*/
public function noAccessAction() {
}
/**
* @return void
*/
public function logoutAction() {
$this->tokenService->clear();
}
}
privilegeTargets:
'TYPO3\Flow\Security\Authorization\Privilege\Method\MethodPrivilege':
'Acme.Demo:AllActions':
matcher: 'method(Acme\Demo\Controller\Controller->(?!(initialize|loggedOut|noAccess)).+Action())'
'Acme.Demo:NoToken':
matcher: 'method(Acme\Demo\Controller\Controller->(?!(initialize|loggedOut|noAccess)).+Action()) && evaluate(current.tokenService.token == null)'
'Acme.Demo:Token':
matcher: 'method(Acme\Demo\Controller\Controller->tokenAction())'
'Acme.Demo:Logout':
matcher: 'method(Acme\Demo\Controller\Controller->logoutAction())'
roles:
'TYPO3.Flow:Everybody':
privileges:
-
privilegeTarget: 'Acme.Demo:Token'
permission: GRANT
-
privilegeTarget: 'Acme.Demo:NoToken'
permission: DENY
-
privilegeTarget: 'Acme.Demo:Logout'
permission: GRANT
TYPO3:
Flow:
aop:
globalObjects:
tokenService: 'Acme\Demo\Service\TokenService'
security:
authentication:
providers:
TokenProvider:
provider: 'Acme\Demo\Security\Authentication\Provider\TokenProvider'
requestPatterns:
controllerObjectName: 'Acme\Demo\Controller\.*'
entryPoint: 'WebRedirect'
entryPointOptions:
routeValues:
'@package': 'Acme.Demo'
'@controller': 'AccessApproval'
'@action': 'noAccess'
'@format': 'html'
<?php
namespace Acme\Demo\Security\Authentication\Token;
/* *
* This script belongs to the TYPO3 Flow package "Acme.Demo". *
* *
* */
use Acme\Demo\Domain\Model\Token;
use TYPO3\Flow\Annotations as Flow;
/**
* An authentication token used for session authentication.
*/
class SessionToken extends \TYPO3\Flow\Security\Authentication\Token\AbstractToken {
/**
* @var array
* @Flow\Transient
*/
protected $credentials = array('token' => '');
/**
* @var Token
*/
protected $token;
/**
* @param \TYPO3\Flow\Mvc\ActionRequest $actionRequest The current action request
* @return void
*/
public function updateCredentials(\TYPO3\Flow\Mvc\ActionRequest $actionRequest) {
if ($actionRequest->getHttpRequest()->getMethod() !== 'GET') {
return;
}
$arguments = $actionRequest->getArguments();
if (!empty($arguments['token'])) {
$this->credentials['token'] = $arguments['token'];
$this->setAuthenticationStatus(self::AUTHENTICATION_NEEDED);
}
}
/**
* @return Token
*/
public function getToken() {
return $this->token;
}
/**
* @param Token $token
* @return void
*/
public function setToken(Token $token) {
$this->token = $token;
}
/**
* Returns a string representation of the token for logging purposes.
*
* @return string
*/
public function __toString() {
return 'Session token';
}
}
<?php
namespace Acme\Demo\Security\Authentication\Provider;
/* *
* This script belongs to the TYPO3 Flow package "Acme.Demo". *
* *
* */
use TYPO3\Flow\Annotations as Flow;
use TYPO3\Flow\Security\Authentication\Provider\AbstractProvider;
use TYPO3\Flow\Security\Authentication\TokenInterface;
use TYPO3\Flow\Security\Exception\UnsupportedAuthenticationTokenException;
use Acme\Demo\Security\Authentication\Token\SessionToken;
class TokenProvider extends AbstractProvider {
/**
* @Flow\Inject
* @var \Acme\Demo\Domain\Repository\TokenRepository
*/
protected $tokenRepository;
/**
* Returns the class names of the tokens this provider can authenticate.
*
* @return array
*/
public function getTokenClassNames() {
return array('Acme\Demo\Security\Authentication\Token\SessionToken');
}
/**
* @param TokenInterface $authenticationToken The token to be authenticated
* @return void
* @throws UnsupportedAuthenticationTokenException
*/
public function authenticate(TokenInterface $authenticationToken) {
if (!$authenticationToken instanceof SessionToken) {
throw new UnsupportedAuthenticationTokenException('This provider cannot authenticate the given token.', 1425564602);
}
/** @var SessionToken $authenticationToken */
$credentials = $authenticationToken->getCredentials();
if (is_array($credentials) && isset($credentials['token'])) {
if ($token = $this->tokenRepository->findByIdentifier($credentials['token'])) {
$authenticationToken->setAuthenticationStatus(TokenInterface::AUTHENTICATION_SUCCESSFUL);
$authenticationToken->setToken($token);
} else {
$authenticationToken->setAuthenticationStatus(TokenInterface::WRONG_CREDENTIALS);
// @TODO log this
}
} elseif ($authenticationToken->getAuthenticationStatus() !== TokenInterface::AUTHENTICATION_SUCCESSFUL) {
$authenticationToken->setAuthenticationStatus(TokenInterface::NO_CREDENTIALS_GIVEN);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment