I am having problems setting up wsse security on my Symfony API. I am following a tutorial Configuring WSSE on Symfony Using FOSRestBundle Based on How to: Create Your Own Authentication Provider
Problems:
How do I use FOSUserBundle with WSSE (especially salt)? I do not want the front to extract the salt of each user who sends the request.
I want the registration route to be anonymously accessible, and every time I try to execute an HTTP request without sending x-wsse, I get an error message:
"message":"A Token was not found in the SecurityContext.",
"class":"Symfony\\Component\\Security\\Core\\Exception\\AuthenticationCredentialsNotFoundException"
application /Config/security.yml
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
wsse_secured:
pattern: ^/
stateless: true
wsse: true
anonymous : false
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_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 }
Wsseprovider
class WsseProvider implements AuthenticationProviderInterface
{
private $userProvider;
private $cacheDir;
public function __construct(UserProviderInterface $userProvider, $cacheDir)
{
$this->userProvider = $userProvider;
$this->cacheDir = $cacheDir;
}
public function authenticate(TokenInterface $token){
$user = $this->userProvider->loadUserByUsername($token->getUsername());
if(!$user){
throw new AuthenticationException("Bad credentials... Did you forgot your username ?");
}
if ($user && $this->validateDigest($token->digest, $token->nonce, $token->created, $user->getPassword())) {
$authenticatedToken = new WsseUserToken($user->getRoles());
$authenticatedToken->setUser($user);
return $authenticatedToken;
}
}
protected function validateDigest($digest, $nonce, $created, $secret){
if (strtotime($created) > time()) {
throw new AuthenticationException("Back to the future...");
}
if (time() - strtotime($created) > 300) {
throw new AuthenticationException("Too late for this timestamp... Watch your watch.");
}
if (file_exists($this->cacheDir.'/'.$nonce) && file_get_contents($this->cacheDir.'/'.$nonce) + 300 > time()) {
throw new NonceExpiredException('Previously used nonce detected');
}
if (!is_dir($this->cacheDir)) {
mkdir($this->cacheDir, 0777, true);
}
file_put_contents($this->cacheDir.'/'.$nonce, time());
$expected = base64_encode(sha1(base64_decode($nonce).$created.$secret, true));
if($digest !== $expected){
throw new AuthenticationException("Bad credentials ! Digest is not as expected.");
}
return true;
}
public function supports(TokenInterface $token){
return $token instanceof WsseUserToken;
}
}
WsseUserToken
class WsseUserToken extends AbstractToken
{
public $created;
public $digest;
public $nonce;
public function __construct(array $roles = array())
{
parent::__construct($roles);
$this->setAuthenticated(count($roles) > 0);
}
public function getCredentials()
{
return '';
}
}
Wsselistist
class WsseListener implements ListenerInterface
{
protected $securityContext;
protected $authenticationManager;
protected $logger;
public function __construct(SecurityContextInterface $securityContext,
AuthenticationManagerInterface $authenticationManager
)
{
$this->securityContext = $securityContext;
$this->authenticationManager = $authenticationManager;
}
public function handle(GetResponseEvent $event)
{
$request = $event->getRequest();
$wsseRegex = '/UsernameToken Username="([^"]+)", PasswordDigest="([^"]+)", Nonce="([^"]+)", Created="([^"]+)"/';
if (!$request->headers->has('x-wsse') || 1 !== preg_match($wsseRegex, $request->headers->get('x-wsse'), $matches) ) {
return;
}
$token = new WsseUserToken();
$token->setUser($matches[1]);
$token->digest = $matches[2];
$token->nonce = $matches[3];
$token->created = $matches[4];
try {
$authToken = $this->authenticationManager->authenticate($token);
$this->securityContext->setToken($authToken);
return;
} catch (AuthenticationException $failed) {
$failedMessage = 'WSSE Login failed for '.$token->getUsername().'. Why ? '.$failed->getMessage();
$response = new Response();
$response->setStatusCode(403);
$response->setContent($failedMessage);
$event->setResponse($response);
return;
}
$response = new Response();
$response->setStatusCode(403);
$event->setResponse($response);
}
}
Any help that really appreciates this is killing me ...
adaba source
share