public function getUniqueId()
 {
     return parent::getUniqueId() . ':' . implode('|', array_map(function ($req) {
         return $req->getUniqueId();
     }, $this->linkRequests));
 }
 public function testMergeFieldInfo()
 {
     $msg = wfMessage('foo');
     $req1 = $this->getMock(AuthenticationRequest::class);
     $req1->required = AuthenticationRequest::REQUIRED;
     $req1->expects($this->any())->method('getFieldInfo')->will($this->returnValue(['string1' => ['type' => 'string', 'label' => $msg, 'help' => $msg], 'string2' => ['type' => 'string', 'label' => $msg, 'help' => $msg], 'optional' => ['type' => 'string', 'label' => $msg, 'help' => $msg, 'optional' => true], 'select' => ['type' => 'select', 'options' => ['foo' => $msg, 'baz' => $msg], 'label' => $msg, 'help' => $msg]]));
     $req2 = $this->getMock(AuthenticationRequest::class);
     $req2->required = AuthenticationRequest::REQUIRED;
     $req2->expects($this->any())->method('getFieldInfo')->will($this->returnValue(['string1' => ['type' => 'string', 'label' => $msg, 'help' => $msg], 'string3' => ['type' => 'string', 'label' => $msg, 'help' => $msg], 'select' => ['type' => 'select', 'options' => ['bar' => $msg, 'baz' => $msg], 'label' => $msg, 'help' => $msg]]));
     $req3 = $this->getMock(AuthenticationRequest::class);
     $req3->required = AuthenticationRequest::REQUIRED;
     $req3->expects($this->any())->method('getFieldInfo')->will($this->returnValue(['string1' => ['type' => 'checkbox', 'label' => $msg, 'help' => $msg]]));
     $req4 = $this->getMock(AuthenticationRequest::class);
     $req4->required = AuthenticationRequest::REQUIRED;
     $req4->expects($this->any())->method('getFieldInfo')->will($this->returnValue([]));
     // Basic combining
     $fields = AuthenticationRequest::mergeFieldInfo([$req1]);
     $expect = $req1->getFieldInfo();
     foreach ($expect as $name => &$options) {
         $options['optional'] = !empty($options['optional']);
     }
     unset($options);
     $this->assertEquals($expect, $fields);
     $fields = AuthenticationRequest::mergeFieldInfo([$req1, $req4]);
     $this->assertEquals($expect, $fields);
     try {
         AuthenticationRequest::mergeFieldInfo([$req1, $req3]);
         $this->fail('Expected exception not thrown');
     } catch (\UnexpectedValueException $ex) {
         $this->assertSame('Field type conflict for "string1", "string" vs "checkbox"', $ex->getMessage());
     }
     $fields = AuthenticationRequest::mergeFieldInfo([$req1, $req2]);
     $expect += $req2->getFieldInfo();
     $expect['string2']['optional'] = false;
     $expect['string3']['optional'] = false;
     $expect['select']['options']['bar'] = $msg;
     $this->assertEquals($expect, $fields);
     // Combining with something not required
     $req1->required = AuthenticationRequest::PRIMARY_REQUIRED;
     $fields = AuthenticationRequest::mergeFieldInfo([$req1]);
     $expect = $req1->getFieldInfo();
     foreach ($expect as $name => &$options) {
         $options['optional'] = true;
     }
     unset($options);
     $this->assertEquals($expect, $fields);
     $fields = AuthenticationRequest::mergeFieldInfo([$req1, $req2]);
     $expect += $req2->getFieldInfo();
     $expect['string1']['optional'] = false;
     $expect['string3']['optional'] = false;
     $expect['select']['optional'] = false;
     $expect['select']['options']['bar'] = $msg;
     $this->assertEquals($expect, $fields);
 }
 /**
  * Try to reset the password
  * @param \User $user
  * @param AuthenticationRequest[] $reqs
  * @return AuthenticationResponse
  */
 protected function tryReset(\User $user, array $reqs)
 {
     $data = $this->manager->getAuthenticationSessionData('reset-pass');
     if (!$data) {
         return AuthenticationResponse::newAbstain();
     }
     if (is_array($data)) {
         $data = (object) $data;
     }
     if (!is_object($data)) {
         throw new \UnexpectedValueException('reset-pass is not valid');
     }
     if (!isset($data->msg)) {
         throw new \UnexpectedValueException('reset-pass msg is missing');
     } elseif (!$data->msg instanceof \Message) {
         throw new \UnexpectedValueException('reset-pass msg is not valid');
     } elseif (!isset($data->hard)) {
         throw new \UnexpectedValueException('reset-pass hard is missing');
     } elseif (isset($data->req) && (!$data->req instanceof PasswordAuthenticationRequest || !array_key_exists('retype', $data->req->getFieldInfo()))) {
         throw new \UnexpectedValueException('reset-pass req is not valid');
     }
     if (!$data->hard) {
         $req = ButtonAuthenticationRequest::getRequestByName($reqs, 'skipReset');
         if ($req) {
             $this->manager->removeAuthenticationSessionData('reset-pass');
             return AuthenticationResponse::newPass();
         }
     }
     $needReq = isset($data->req) ? $data->req : new PasswordAuthenticationRequest();
     if (!$needReq->action) {
         $needReq->action = AuthManager::ACTION_CHANGE;
     }
     $needReq->required = $data->hard ? AuthenticationRequest::REQUIRED : AuthenticationRequest::OPTIONAL;
     $needReqs = [$needReq];
     if (!$data->hard) {
         $needReqs[] = new ButtonAuthenticationRequest('skipReset', wfMessage('authprovider-resetpass-skip-label'), wfMessage('authprovider-resetpass-skip-help'));
     }
     $req = AuthenticationRequest::getRequestByClass($reqs, get_class($needReq));
     if (!$req || !array_key_exists('retype', $req->getFieldInfo())) {
         return AuthenticationResponse::newUI($needReqs, $data->msg, 'warning');
     }
     if ($req->password !== $req->retype) {
         return AuthenticationResponse::newUI($needReqs, new \Message('badretype'), 'error');
     }
     $req->username = $user->getName();
     $status = $this->manager->allowsAuthenticationDataChange($req);
     if (!$status->isGood()) {
         return AuthenticationResponse::newUI($needReqs, $status->getMessage(), 'error');
     }
     $this->manager->changeAuthenticationData($req);
     $this->manager->removeAuthenticationSessionData('reset-pass');
     return AuthenticationResponse::newPass();
 }
 public function describeCredentials()
 {
     return ['provider' => wfMessage('authmanager-provider-temporarypassword'), 'account' => new \RawMessage('$1', [$this->username])] + parent::describeCredentials();
 }