/**
  * Create Positive Identity Assertion
  * implements http://openid.net/specs/openid-authentication-2_0.html#positive_assertions
  * @return OpenIdPositiveAssertionResponse
  * @throws InvalidAssociationTypeException
  */
 private function doAssertion()
 {
     $currentUser = $this->auth_service->getCurrentUser();
     $context = new ResponseContext();
     //initial signature params
     $context->addSignParam(OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_OpEndpoint));
     $context->addSignParam(OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Realm));
     $context->addSignParam(OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ReturnTo));
     $context->addSignParam(OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Nonce));
     $context->addSignParam(OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_AssocHandle));
     $context->addSignParam(OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_ClaimedId));
     $context->addSignParam(OpenIdProtocol::param(OpenIdProtocol::OpenIDProtocol_Identity));
     $op_endpoint = $this->server_configuration_service->getOPEndpointURL();
     $identity = $this->server_configuration_service->getUserIdentityEndpointURL($currentUser->getIdentifier());
     $nonce = $this->nonce_service->generateNonce();
     $realm = $this->current_request->getRealm();
     $response = new OpenIdPositiveAssertionResponse($op_endpoint, $identity, $identity, $this->current_request->getReturnTo(), $nonce->getRawFormat(), $realm);
     foreach ($this->extensions as $ext) {
         $ext->prepareResponse($this->current_request, $response, $context);
     }
     //check former assoc handle...
     if (is_null($assoc_handle = $this->current_request->getAssocHandle()) || is_null($association = $this->association_service->getAssociation($assoc_handle))) {
         //create private association ...
         $association = $this->association_service->addAssociation(AssociationFactory::getInstance()->buildPrivateAssociation($realm, $this->server_configuration_service->getConfigValue("Private.Association.Lifetime")));
         $response->setAssocHandle($association->getHandle());
         if (!empty($assoc_handle)) {
             $response->setInvalidateHandle($assoc_handle);
         }
     } else {
         if ($association->getType() != IAssociation::TypeSession) {
             throw new InvalidAssociationTypeException(OpenIdErrorMessages::InvalidAssociationTypeMessage);
         }
         $response->setAssocHandle($assoc_handle);
     }
     //create signature ...
     OpenIdSignatureBuilder::build($context, $association->getMacFunction(), $association->getSecret(), $response);
     /*
      * To prevent replay attacks, the OP MUST NOT issue more than one verification response for each
      * authentication response it had previously issued. An authentication response and its matching
      * verification request may be identified by their "openid.response_nonce" values.
      * so associate $nonce with signature and realm
      */
     $this->nonce_service->associateNonce($nonce, $response->getSig(), $realm);
     //do cleaning ...
     $this->memento_service->clearCurrentRequest();
     $this->auth_service->clearUserAuthorizationResponse();
     return $response;
 }
 protected function internalHandle(OpenIdMessage $message)
 {
     $this->current_request = null;
     try {
         $this->current_request = new OpenIdCheckAuthenticationRequest($message, $this->openid_configuration_service->getOPEndpointURL());
         if (!$this->current_request->isValid()) {
             throw new InvalidOpenIdMessageException(OpenIdErrorMessages::InvalidOpenIdCheckAuthenticationRequestMessage);
         }
         /**
          *  For verifying signatures an OP MUST only use private associations and MUST NOT
          *  use associations that have shared keys. If the verification request contains a handle
          * for a shared association, it means the Relying Party no longer knows the shared secret,
          * or an entity other than the RP (e.g. an attacker) has established this association with
          * the OP.
          * To prevent replay attacks, the OP MUST NOT issue more than one verification response for each
          * authentication response it had previously issued. An authentication response and its matching
          * verification request may be identified by their "openid.response_nonce" values.
          */
         $claimed_assoc = $this->current_request->getAssocHandle();
         $claimed_realm = $this->current_request->getRealm();
         $stored_assoc = $this->association_service->getAssociation($claimed_assoc, $claimed_realm);
         if (is_null($stored_assoc) || $stored_assoc->getType() != IAssociation::TypePrivate) {
             throw new InvalidAssociationTypeException(OpenIdErrorMessages::InvalidAssociationTypeMessage);
         }
         $claimed_nonce = new OpenIdNonce($this->current_request->getNonce());
         if (!$claimed_nonce->isValid(intval($this->configuration_service->getConfigValue('Nonce.Lifetime')))) {
             throw new InvalidNonce();
         }
         $this->nonce_service->lockNonce($claimed_nonce);
         $claimed_sig = $this->current_request->getSig();
         $claimed_invalidate_handle = $this->current_request->getInvalidateHandle();
         if (!is_null($claimed_invalidate_handle) && !empty($claimed_invalidate_handle)) {
             $invalidate_stored_assoc = $this->association_service->getAssociation($claimed_invalidate_handle);
             if (!is_null($invalidate_stored_assoc)) {
                 $claimed_invalidate_handle = null;
             }
         }
         $this->nonce_service->markNonceAsInvalid($claimed_nonce, $claimed_sig, $claimed_realm);
         $res = OpenIdSignatureBuilder::verify($this->current_request, $stored_assoc->getMacFunction(), $stored_assoc->getSecret(), $claimed_sig);
         //delete association
         $this->association_service->deleteAssociation($claimed_assoc);
         $is_valid = $res ? 'true' : 'false';
         return new OpenIdCheckAuthenticationResponse($is_valid, $claimed_invalidate_handle);
     } catch (InvalidAssociationTypeException $inv_assoc_ex) {
         $this->checkpoint_service->trackException($inv_assoc_ex);
         $this->log_service->warning($inv_assoc_ex);
         $response = new OpenIdDirectGenericErrorResponse($inv_assoc_ex->getMessage());
         if (!is_null($this->current_request)) {
             $this->log_service->error_msg("current request: " . $this->current_request->toString());
         }
         return $response;
     } catch (ReplayAttackException $replay_ex) {
         $this->checkpoint_service->trackException($replay_ex);
         $this->log_service->warning($replay_ex);
         $response = new OpenIdDirectGenericErrorResponse($replay_ex->getMessage());
         if (!is_null($this->current_request)) {
             $this->log_service->error_msg("current request: " . $this->current_request->toString());
         }
         return $response;
     } catch (InvalidNonce $inv_nonce_ex) {
         $this->checkpoint_service->trackException($inv_nonce_ex);
         $this->log_service->error($inv_nonce_ex);
         $response = new OpenIdDirectGenericErrorResponse($inv_nonce_ex->getMessage());
         if (!is_null($this->current_request)) {
             $this->log_service->error_msg("current request: " . $this->current_request->toString());
         }
         return $response;
     } catch (InvalidOpenIdMessageException $inv_msg_ex) {
         $this->checkpoint_service->trackException($inv_msg_ex);
         $this->log_service->error($inv_msg_ex);
         $response = new OpenIdDirectGenericErrorResponse($inv_msg_ex->getMessage());
         if (!is_null($this->current_request)) {
             $this->log_service->error_msg("current request: " . $this->current_request->toString());
         }
         return $response;
     } catch (Exception $ex) {
         $this->checkpoint_service->trackException($ex);
         $this->log_service->error($ex);
         if (!is_null($this->current_request)) {
             $this->log_service->error_msg("current request: " . $this->current_request->toString());
         }
         return new OpenIdDirectGenericErrorResponse("Server Error");
     }
 }