/** * 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"); } }