/** * Test setting a requesterID. */ public function testRequesterIdIsReadCorrectly() { $requesterId = array('https://engine.demo.openconext.org/authentication/sp/metadata', 'https://shib.example.edu/SSO/Metadata'); $xmlRequest = <<<AUTHNREQUEST <samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="_1234567890abvdefghijkl" Version="2.0" IssueInstant="2015-05-11T09:02:36Z" Destination="https://some.sp.invalid/acs"> <saml:Issuer>https://some.sp.invalid/metadata</saml:Issuer> <samlp:Scoping> <samlp:RequesterID>https://engine.demo.openconext.org/authentication/sp/metadata</samlp:RequesterID> <samlp:RequesterID>https://shib.example.edu/SSO/Metadata</samlp:RequesterID> </samlp:Scoping> </samlp:AuthnRequest> AUTHNREQUEST; $authnRequest = new AuthnRequest(DOMDocumentFactory::fromString($xmlRequest)->firstChild); $this->assertEquals($requesterId, $authnRequest->getRequesterID()); }
/** * @param string $returnTo Where to have IdP send user after login * @param \yii\web\Request|null $request * @return \Sil\IdpPw\Common\Auth\User * @throws \Sil\IdpPw\Common\Auth\InvalidLoginException * @throws RedirectException */ public function login($returnTo, Request $request = null) { $container = new SamlContainer(); ContainerSingleton::setContainer($container); $request = new AuthnRequest(); $request->setId($container->generateId()); $request->setIssuer($this->entityId); $request->setDestination($this->ssoUrl); $request->setRelayState($returnTo); /* * Sign request if spCertificate and spPrivateKey are provided */ if ($this->signRequest) { $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, ['type' => 'private']); $key->loadKey($this->spPrivateKey, false); $request->setSignatureKey($key); } try { /* * Check for SAMLRequest or SAMLResponse to see if user is returning after login */ $binding = new HTTPPost(); /** @var \SAML2\Response $response */ $response = $binding->receive(); } catch (\Exception $e) { /* * User was not logged in, so redirect to IdP for login */ $binding = new HTTPRedirect(); $url = $binding->getRedirectURL($request); throw new RedirectException($url); } try { /* * If needed, check if response is signed */ if ($this->checkResponseSigning) { $idpKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, ['type' => 'public']); $idpKey->loadKey($this->idpCertificate, false, true); if (!$response->validate($idpKey)) { throw new \Exception('SAML response was not signed properly', 1459884735); } } /** @var \SAML2\Assertion[]|\SAML2\EncryptedAssertion[] $assertions */ $assertions = $response->getAssertions(); /* * If requiring encrypted assertion, use key to decrypt it */ if ($this->requireEncryptedAssertion) { $decryptKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, ['type' => 'private']); $decryptKey->loadKey($this->spPrivateKey, false, false); if (!$assertions[0] instanceof EncryptedAssertion) { throw new \Exception('Response assertion is required to be encrypted but was not', 1459884392); } $assertion = $assertions[0]->getAssertion($decryptKey); } else { $assertion = $assertions[0]; } /* * Get attributes using mapping config, make sure expected fields * are present, and return as new User */ /** @var \SAML2\Assertion $assertion */ $samlAttrs = $assertion->getAttributes(); $normalizedAttrs = $this->extractSamlAttributes($samlAttrs, $this->attributeMap); $this->assertHasRequiredSamlAttributes($normalizedAttrs, $this->attributeMap); $authUser = new AuthUser(); $authUser->firstName = $normalizedAttrs['first_name']; $authUser->lastName = $normalizedAttrs['last_name']; $authUser->email = $normalizedAttrs['email']; $authUser->employeeId = $normalizedAttrs['employee_id']; $authUser->idpUsername = $normalizedAttrs['idp_username']; return $authUser; } catch (\Exception $e) { /* * An error occurred processing SAML data */ throw new InvalidLoginException($e->getMessage(), 1459803743); } }
/** * Test setting a requesterID. */ public function testRequesterId() { // basic AuthnRequest $request = new AuthnRequest(); $request->setIssuer('https://gateway.example.org/saml20/sp/metadata'); $request->setDestination('https://tiqr.example.org/idp/profile/saml2/Redirect/SSO'); $request->setRequesterID(array('https://engine.demo.openconext.org/authentication/sp/metadata', 'https://shib.example.edu/SSO/Metadata')); $expectedStructureDocument = new DOMDocument(); $expectedStructureDocument->loadXML(<<<AUTHNREQUEST <samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" ID="" Version="" IssueInstant="" Destination=""> <saml:Issuer></saml:Issuer> <samlp:Scoping> <samlp:RequesterID>https://engine.demo.openconext.org/authentication/sp/metadata</samlp:RequesterID> <samlp:RequesterID>https://shib.example.edu/SSO/Metadata</samlp:RequesterID> </samlp:Scoping> </samlp:AuthnRequest> AUTHNREQUEST ); $expectedStructure = $expectedStructureDocument->documentElement; $requestStructure = $request->toUnsignedXML(); $this->assertEqualXMLStructure($expectedStructure, $requestStructure); }