/** * @param \Symfony\Component\HttpFoundation\Request $request * @throws \RuntimeException * @throws \InvalidArgumentException if cannot manage the Request * @return \Symfony\Component\HttpFoundation\Response|SamlSpInfo|null */ public function manage(Request $request) { if (!$this->supports($request)) { throw new \InvalidArgumentException('Unsupported request'); } $logoutRequest = $this->receiveRequest($request); $serviceInfo = $this->getServiceInfo($logoutRequest); $this->validateLogoutRequest($serviceInfo, $logoutRequest); $arrStates = $this->getSSOState($serviceInfo, $logoutRequest->getNameID()->getValue(), $logoutRequest->getSessionIndex()); $this->deleteSSOState($arrStates); $logoutResponse = new LogoutResponse(); $logoutResponse->setID(Helper::generateID()); $logoutResponse->setIssuer($serviceInfo->getSpProvider()->getEntityDescriptor()->getEntityID()); $logoutResponse->setInResponseTo($logoutRequest->getID()); $arrSLO = $serviceInfo->getIdpProvider()->getEntityDescriptor()->getFirstIdpSsoDescriptor()->findSingleLogoutServices(); /** @var $slo SingleLogoutService */ $slo = array_pop($arrSLO); $logoutResponse->setDestination($slo->getLocation()); $status = new Status(); $status->setSuccess(); $logoutResponse->setStatus($status); $context = new SerializationContext(); $logoutResponse->getXml($context->getDocument(), $context); $xml = $context->getDocument()->saveXML(); return new Response($xml, 200, array('Content-Type' => 'application/xml')); }
/** * @param AbstractService $service * @return SpSsoDescriptor * @throws \InvalidArgumentException */ public function addService(AbstractService $service) { $class = Helper::getClassNameOnly($service); if ($class != 'SingleLogoutService' && $class != 'SingleSignOnService') { throw new \InvalidArgumentException("Invalid service type {$class} for IDPSSODescriptor"); } return parent::addService($service); }
/** * @param string $class * @param int|bool $count * @return GetXmlInterface[]|LoadFromXmlInterface[] */ public function getItemsByType($class, $count = false) { $result = array(); foreach ($this->items as $item) { if (Helper::doClassNameMatch($item, $class)) { $result[] = $item; if ($count && count($result) >= $count) { break; } } } return $result; }
/** * @param \DOMNode $parent * @param \AerialShip\LightSaml\Meta\SerializationContext $context * @return \DOMElement */ function getXml(\DOMNode $parent, SerializationContext $context) { $result = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:AuthnStatement'); $parent->appendChild($result); $result->setAttribute('AuthnInstant', Helper::time2string($this->getAuthnInstant())); if ($this->getSessionIndex()) { $result->setAttribute('SessionIndex', $this->getSessionIndex()); } $authnContextNode = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:AuthnContext'); $result->appendChild($authnContextNode); $refNode = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:AuthnContextClassRef', $this->getAuthnContext()); $authnContextNode->appendChild($refNode); return $result; }
/** * @return AuthnRequest */ public function build() { $result = new AuthnRequest(); $edSP = $this->getEdSP(); $result->setID(Helper::generateID()); $result->setDestination($this->getDestination()); $result->setIssueInstant(time()); $asc = $this->getAssertionConsumerService(); $result->setAssertionConsumerServiceURL($asc->getLocation()); $result->setProtocolBinding($asc->getBinding()); $result->setIssuer($edSP->getEntityID()); if ($this->spMeta->getNameIdFormat()) { $result->setNameIdPolicyFormat($this->spMeta->getNameIdFormat()); } return $result; }
/** * @param \Symfony\Component\HttpFoundation\Request $request * @throws \RuntimeException * @throws \InvalidArgumentException if cannot manage the Request * @return \Symfony\Component\HttpFoundation\Response|SamlSpInfo|null */ public function manage(Request $request) { if (!$this->supports($request)) { throw new \InvalidArgumentException('Unsupported request'); } $logoutRequest = $this->receiveRequest($request); $serviceInfo = $this->getServiceInfo($logoutRequest, $request); $this->validateLogoutRequest($serviceInfo, $logoutRequest); $arrStates = $this->getSSOState($serviceInfo, $logoutRequest->getNameID()->getValue(), $logoutRequest->getSessionIndex()); $this->deleteSSOState($arrStates); $logoutResponse = new LogoutResponse(); $logoutResponse->setID(Helper::generateID()); $logoutResponse->setIssuer($serviceInfo->getSpProvider()->getEntityDescriptor()->getEntityID()); $logoutResponse->setInResponseTo($logoutRequest->getID()); $logoutResponse->setRelayState($logoutRequest->getRelayState()); $arrSLO = $serviceInfo->getIdpProvider()->getEntityDescriptor()->getFirstIdpSsoDescriptor()->findSingleLogoutServices(); /** @var $slo SingleLogoutService */ $slo = array_pop($arrSLO); $logoutResponse->setDestination($slo->getLocation()); $status = new Status(); $status->setSuccess(); $logoutResponse->setStatus($status); // Log the user out $request->getSession()->invalidate(); $this->securityContext->setToken(null); // Return the response to SLO Service $bindingType = $serviceInfo->getSpMetaProvider()->getSpMeta()->getResponseBinding(); if ($bindingType) { $detector = new BindingDetector(); $binding = $detector->instantiate($bindingType); } else { $binding = new HttpRedirect(); } $bindingResponse = $binding->send($logoutResponse); if ($bindingResponse instanceof PostResponse) { return new Response($bindingResponse->render()); } else { if ($bindingResponse instanceof RedirectResponse) { return new RedirectResponse($bindingResponse->getDestination()); } else { $context = new SerializationContext(); $logoutResponse->getXml($context->getDocument(), $context); $xml = $context->getDocument()->saveXML(); return new Response($xml, 200, array('Content-Type' => 'application/xml')); } } }
/** * @param string $nameIDValue * @param string|null $nameIDFormat * @param string|null $sessionIndex * @param string|null $reason * @return LogoutRequest */ public function build($nameIDValue, $nameIDFormat = null, $sessionIndex = null, $reason = null) { $result = new LogoutRequest(); $edSP = $this->getEdSP(); $result->setID(Helper::generateID()); $result->setDestination($this->getDestination()); $result->setIssueInstant(time()); if ($reason) { $result->setReason($reason); } if ($sessionIndex) { $result->setSessionIndex($sessionIndex); } $nameID = new NameID(); $nameID->setValue($nameIDValue); if ($nameIDFormat) { $nameID->setFormat($nameIDFormat); } $result->setNameID($nameID); $result->setIssuer($edSP->getEntityID()); return $result; }
/** * @param string $class * @param string|null $binding * @return AbstractService[] */ public function findServices($class, $binding) { $result = array(); foreach ($this->getServices() as $service) { if (Helper::doClassNameMatch($service, $class)) { if (!$binding || $binding == $service->getBinding()) { $result[] = $service; } } } return $result; }
/** * @param \DOMNode $parent * @param \AerialShip\LightSaml\Meta\SerializationContext $context * @return \DOMElement */ function getXml(\DOMNode $parent, SerializationContext $context) { $result = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:SubjectConfirmationData'); $parent->appendChild($result); if ($this->getNotBefore()) { $result->setAttribute('NotBefore', Helper::time2string($this->getNotBefore())); } if ($this->getNotOnOrAfter()) { $result->setAttribute('NotOnOrAfter', Helper::time2string($this->getNotOnOrAfter())); } foreach (array('Recipient', 'InResponseTo', 'Address') as $name) { $method = "get{$name}"; if ($this->{$method}()) { $result->setAttribute($name, $this->{$method}()); } } return $result; }
function getXml(\DOMNode $parent, SerializationContext $context) { $result = parent::getXml($parent, $context); if ($this->getNotOnOrAfter()) { $result->setAttribute('NotOnOrAfter', Helper::time2string($this->getNotOnOrAfter())); } if ($this->getReason()) { $result->setAttribute('Reason', $this->getReason()); } if ($this->getNameID()) { $result->appendChild($this->getNameID()->getXml($parent, $context)); } if ($this->getSessionIndex()) { $sessionIndex = $context->getDocument()->createElementNS(Protocol::SAML2, 'samlp:SessionIndex', $this->getSessionIndex()); $result->appendChild($sessionIndex); } return $result; }
/** * @param \DOMElement $xml * @throws \AerialShip\LightSaml\Error\InvalidXmlException */ public function loadFromXml(\DOMElement $xml) { $name = $this->getXmlNodeLocalName(); if (($pos = strpos($name, ':')) !== false) { $name = substr($name, $pos + 1); } if ($xml->localName != $name) { throw new InvalidXmlException('Expected ' . $this->getXmlNodeLocalName() . ' node but got ' . $xml->localName); } if ($this->getXmlNodeNamespace() && $xml->namespaceURI != $this->getXmlNodeNamespace()) { throw new InvalidXmlException('Expected ' . $this->getXmlNodeNamespace() . ' namespace but got' . $xml->namespaceURI); } $this->checkRequiredAttributes($xml, array('ID', 'Version', 'IssueInstant')); $this->setID($xml->getAttribute('ID')); $this->setVersion($xml->getAttribute('Version')); $this->setIssueInstant(Helper::parseSAMLTime($xml->getAttribute('IssueInstant'))); $this->setDestination($xml->getAttribute('Destination')); $this->iterateChildrenElements($xml, function (\DOMElement $node) { if ($node->localName == 'Issuer' && $node->namespaceURI == Protocol::NS_ASSERTION) { $this->setIssuer($node->textContent); } }); }
/** * @param \DOMElement $xml * @throws \AerialShip\LightSaml\Error\InvalidXmlException */ function loadFromXml(\DOMElement $xml) { if ($xml->localName != 'EntitiesDescriptor' || $xml->namespaceURI != Protocol::NS_METADATA) { throw new InvalidXmlException('Expected EntitiesDescriptor element and ' . Protocol::NS_METADATA . ' namespace but got ' . $xml->localName); } if ($xml->hasAttribute('validUntil')) { $this->setValidUntil(Helper::parseSAMLTime($xml->getAttribute('validUntil'))); } if ($xml->hasAttribute('cacheDuration')) { $this->setCacheDuration($xml->getAttribute('cacheDuration')); } if ($xml->hasAttribute('ID')) { $this->setId($xml->getAttribute('ID')); } if ($xml->hasAttribute('Name')) { $this->setName($xml->getAttribute('Name')); } $this->items = array(); $this->loadXmlChildren($xml, array(array('node' => array('name' => 'EntitiesDescriptor', 'ns' => Protocol::NS_METADATA), 'class' => '\\AerialShip\\LightSaml\\Model\\Metadata\\EntitiesDescriptor'), array('node' => array('name' => 'EntityDescriptor', 'ns' => Protocol::NS_METADATA), 'class' => '\\AerialShip\\LightSaml\\Model\\Metadata\\EntityDescriptor')), function (LoadFromXmlInterface $obj) { $this->addItem($obj); }); if (empty($this->items)) { throw new InvalidXmlException('Expected at least one of EntityDescriptor or EntitiesDescriptor'); } }
/** * @param \DOMNode $parent * @param \AerialShip\LightSaml\Meta\SerializationContext $context * @throws \AerialShip\LightSaml\Error\InvalidAssertionException * @return \DOMElement */ function getXml(\DOMNode $parent, SerializationContext $context) { $this->prepareForXml(); $result = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:Assertion'); $parent->appendChild($result); $result->setAttribute('ID', $this->getID()); $result->setAttribute('Version', $this->getVersion()); $result->setAttribute('IssueInstant', Helper::time2string($this->getIssueInstant())); $issuerNode = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:Issuer', $this->getIssuer()); $result->appendChild($issuerNode); $this->getSubject()->getXml($result, $context); $conditionsNode = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:Conditions'); $result->appendChild($conditionsNode); $conditionsNode->setAttribute('NotBefore', Helper::time2string($this->getNotBefore())); $conditionsNode->setAttribute('NotOnOrAfter', Helper::time2string($this->getNotOnOrAfter())); if ($this->getValidAudience()) { $audienceRestrictionNode = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'AudienceRestriction'); $conditionsNode->appendChild($audienceRestrictionNode); foreach ($this->getValidAudience() as $v) { $audienceNode = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'Audience', $v); $audienceRestrictionNode->appendChild($audienceNode); } } $attributeStatementNode = $context->getDocument()->createElementNS(Protocol::NS_ASSERTION, 'saml:AttributeStatement'); $result->appendChild($attributeStatementNode); foreach ($this->getAllAttributes() as $attribute) { $attribute->getXml($attributeStatementNode, $context); } $this->getAuthnStatement()->getXml($result, $context); if ($signature = $this->getSignature()) { if (!$signature instanceof SignatureCreator) { throw new InvalidAssertionException('Signature must be SignatureCreator'); } $signature->getXml($result, $context); } return $result; }