public function testChangeCredentialWithToken()
 {
     //complete the password recovery
     $text = file_get_contents(__DIR__ . '/../../../../email/test_mail.tmp');
     preg_match('/\\/rest\\/forgotcredentialtoken\\/[a-zA-Z0-9]+/', $text, $match);
     $accept = new Accept();
     $accept->addMediaType('application/json');
     $this->getRequest()->setMethod(Request::METHOD_PUT)->setContent('{"credential": "newPassword1"}')->getHeaders()->addHeaders([$accept, ContentType::fromString('Content-type: application/json')]);
     $this->dispatch($match[0]);
     $response = $this->getResponse();
     $result = json_decode($response->getContent(), true);
     $this->assertFalse(isset($result));
     $this->assertResponseStatusCode(204);
     $identity = $this->documentManager->getRepository('Sds\\IdentityModule\\DataModel\\Identity')->findOneBy(['identityName' => 'toby']);
     $this->assertTrue(Hash::hashCredential($identity, 'newPassword1') == $identity->getCredential());
 }
 /**
  * This will start the credential reset process for an identity.
  * If the identity is found in the db, a new token is created, and
  * that token is sent to the identity's email.
  *
  * @param type $data
  * @return type
  * @throws Exception\LoginFailedException
  */
 public function create($data)
 {
     $documentManager = $this->options->getDocumentManager();
     $identityMetadata = $documentManager->getClassMetadata($this->options->getIdentityClass());
     $criteria = [];
     if (isset($data['identityName']) && !$data['identityName'] == '') {
         $criteria['identityName'] = $data['identityName'];
     }
     if (isset($data['email']) && $data['email'] != '') {
         $criteria['email'] = BlockCipherService::encryptValue($data['email'], $identityMetadata->crypt['blockCipher']['email']);
     }
     if (count($criteria) == 0) {
         throw new Exception\InvalidArgumentException('Either identityName or email must be provided');
     }
     $identityRepository = $documentManager->getRepository($this->options->getIdentityClass());
     $identity = $identityRepository->findOneBy($criteria);
     if (!isset($identity)) {
         throw new Exception\DocumentNotFoundException();
     }
     // create unique recovery code
     $code = base64_encode(Hash::hash(time(), $identity->getIdentityName()));
     $code = substr($code, 0, strlen($code) - 2);
     $expiry = $this->options->getExpiry();
     // delete any existing tokens for the identity
     $documentManager->createQueryBuilder($this->options->getDocumentClass())->remove()->field('identityName')->equals($identity->getIdentityName())->getQuery()->execute();
     parent::create(['code' => $code, 'identityName' => $identity->getIdentityName(), 'expires' => $expiry + time()]);
     //remove the Location header so the token isn't exposed in the response
     $headers = $this->response->getHeaders();
     $headers->removeHeader($headers->get('Location'));
     $link = '/rest/' . $this->options->getEndpoint() . '/' . $code;
     // Create email body
     $body = new ViewModel(['identityName' => $identity->getIdentityName(), 'link' => $link, 'hours' => $expiry / (60 * 60)]);
     $body->setTemplate('email/forgot-credential');
     // Send the email
     $mail = new Message();
     $mail->setBody($this->options->getEmailRenderer()->render($body))->setFrom($this->options->getMailFrom())->addTo(BlockCipherService::decryptValue($identity->getEmail(), $identityMetadata->crypt['blockCipher']['email']))->setSubject($this->options->getMailSubject());
     $this->options->getMailTransport()->send($mail);
     $this->response->setStatusCode(201);
     return $this->response;
 }