Example #1
1
 /**
  * Attempts to log the authenticated CAS user into Drupal.
  *
  * This method should be used to login a user after they have successfully
  * authenticated with the CAS server.
  *
  * @param CasPropertyBag $property_bag
  *   CasPropertyBag containing username and attributes from CAS.
  * @param string $ticket
  *   The service ticket.
  *
  * @throws CasLoginException
  *   Thrown if there was a problem logging in the user.
  */
 public function loginToDrupal(CasPropertyBag $property_bag, $ticket)
 {
     // Dispatch an event that allows modules to change user data we received
     // from CAS before attempting to use it to load a Drupal user.
     // Auto-registration can also be disabled for this user if their account
     // does not exist.
     $user_load_event = new CasUserLoadEvent($property_bag);
     $this->eventDispatcher->dispatch(CasHelper::EVENT_USER_LOAD, $user_load_event);
     $account = $this->userLoadByName($property_bag->getUsername());
     if (!$account) {
         $config = $this->settings->get('cas.settings');
         if ($config->get('user_accounts.auto_register') === TRUE) {
             if ($user_load_event->allowAutoRegister) {
                 $account = $this->registerUser($property_bag->getUsername(), $config->get('user_accounts.auto_assigned_roles'));
             } else {
                 throw new CasLoginException("Cannot register user, an event listener denied access.");
             }
         } else {
             throw new CasLoginException("Cannot login, local Drupal user account does not exist.");
         }
     }
     // Dispatch an event that allows modules to prevent this user from logging
     // in and/or alter the user entity before we save it.
     $pre_auth_event = new CasPreAuthEvent($account, $property_bag);
     $this->eventDispatcher->dispatch(CasHelper::EVENT_PRE_AUTH, $pre_auth_event);
     // Save user entity since event listeners may have altered it.
     $account->save();
     if (!$pre_auth_event->allowLogin) {
         throw new CasLoginException("Cannot login, an event listener denied access.");
     }
     $this->userLoginFinalize($account);
     $this->storeLoginSessionData($this->session->getId(), $ticket);
 }
Example #2
0
 /**
  * Test setting the attributes array.
  *
  * @covers ::setAttributes
  */
 public function testSetAttributes()
 {
     $bag = new CasPropertyBag($this->randomMachineName(8));
     $attributes = array('foo' => array('bar'), 'baz' => array('quux, foobar'));
     $bag->setAttributes($attributes);
     $this->assertEquals($attributes, \PHPUnit_Framework_Assert::readAttribute($bag, 'attributes'));
 }
Example #3
0
 /**
  * Attempts to log the authenticated CAS user into Drupal.
  *
  * This method should be used to login a user after they have successfully
  * authenticated with the CAS server.
  *
  * @param CasPropertyBag $property_bag
  *   CasPropertyBag containing username and attributes from CAS.
  *
  * @throws CasLoginException
  */
 public function loginToDrupal(CasPropertyBag $property_bag, $ticket)
 {
     $this->eventDispatcher->dispatch(CasHelper::CAS_PROPERTY_ALTER, new CasPropertyEvent($property_bag));
     $account = $this->userLoadByName($property_bag->getUsername());
     if (!$account) {
         $config = $this->settings->get('cas.settings');
         if ($config->get('user_accounts.auto_register') === TRUE) {
             if (!$property_bag->getRegisterStatus()) {
                 $_SESSION['cas_temp_disable'] = TRUE;
                 throw new CasLoginException("Cannot register user, an event listener denied access.");
             }
             $account = $this->registerUser($property_bag->getUsername());
         } else {
             throw new CasLoginException("Cannot login, local Drupal user account does not exist.");
         }
     }
     $this->eventDispatcher->dispatch(CasHelper::CAS_USER_ALTER, new CasUserEvent($account, $property_bag));
     $account->save();
     if (!$property_bag->getLoginStatus()) {
         $_SESSION['cas_temp_disable'] = TRUE;
         throw new CasLoginException("Cannot login, an event listener denied access.");
     }
     $this->userLoginFinalize($account);
     $this->storeLoginSessionData($this->sessionManager->getId(), $ticket);
 }
Example #4
0
 /**
  * Test parsing out CAS attributes from response.
  *
  * @covers ::validateVersion2
  * @covers ::parseAttributes
  */
 public function testParseAttributes()
 {
     $ticket = $this->randomMachineName(8);
     $service_params = array();
     $response = "<cas:serviceResponse xmlns:cas='http://example.com/cas'>\n        <cas:authenticationSuccess>\n          <cas:user>username</cas:user>\n          <cas:attributes>\n            <cas:email>foo@example.com</cas:email>\n            <cas:memberof>cn=foo,o=example</cas:memberof>\n            <cas:memberof>cn=bar,o=example</cas:memberof>\n          </cas:attributes>\n        </cas:authenticationSuccess>\n       </cas:serviceResponse>";
     $mock = new MockHandler([new Response(200, array(), $response)]);
     $handler = HandlerStack::create($mock);
     $httpClient = new Client(['handler' => $handler]);
     $casHelper = $this->getMockBuilder('\\Drupal\\cas\\Service\\CasHelper')->disableOriginalConstructor()->getMock();
     $casHelper->expects($this->any())->method('getCasProtocolVersion')->willReturn('2.0');
     $casValidator = new CasValidator($httpClient, $casHelper);
     $expected_bag = new CasPropertyBag('username');
     $expected_bag->setAttributes(array('email' => array('*****@*****.**'), 'memberof' => array('cn=foo,o=example', 'cn=bar,o=example')));
     $actual_bag = $casValidator->validateTicket($ticket, $service_params);
     $this->assertEquals($expected_bag, $actual_bag);
 }
Example #5
0
 /**
  * Test setting the register status.
  *
  * @covers ::setRegisterStatus
  */
 public function testSetRegisterStatus()
 {
     $bag = new CasPropertyBag($this->randomMachineName(8));
     $bag->setRegisterStatus(FALSE);
     $this->assertEquals(FALSE, \PHPUnit_Framework_Assert::readAttribute($bag, 'registerStatus'));
 }
Example #6
0
 /**
  * Provides parameters and exceptions for testLoginToDrupalListenerDenied
  *
  * @return array
  *   Parameters and exceptions
  *
  * @see \Drupal\Tests\cas\Unit\Service\CasLoginTest::testLoginToDrupalListenerDenied
  */
 public function loginToDrupalListenerDeniedDataProvider()
 {
     // Test denying login access.
     $bag1 = new CasPropertyBag($this->randomMachineName(8));
     $bag1->setLoginStatus(FALSE);
     $message1 = 'Cannot login, an event listener denied access.';
     // Test denying register access.
     $bag2 = new CasPropertyBag($this->randomMachineName(8));
     $bag2->setRegisterStatus(FALSE);
     $message2 = 'Cannot register user, an event listener denied access.';
     return array(array($bag1, $message1), array($bag2, $message2));
 }
Example #7
0
 /**
  * Validation of a service ticket for Version 2 of the CAS protocol.
  *
  * @param string $data
  *   The raw validation response data from CAS server.
  *
  * @return array
  *   An array containing validation result data from the CAS server.
  * @throws CasValidateException
  */
 private function validateVersion2($data)
 {
     $dom = new \DOMDocument();
     $dom->preserveWhiteSpace = FALSE;
     $dom->encoding = "utf-8";
     // Suppress errors from this function, as we intend to throw our own
     // exception.
     if (@$dom->loadXML($data) === FALSE) {
         throw new CasValidateException("XML from CAS server is not valid.");
     }
     $failure_elements = $dom->getElementsByTagName('authenticationFailure');
     if ($failure_elements->length > 0) {
         // Failed validation, extract the message and toss exception.
         $failure_element = $failure_elements->item(0);
         $error_code = $failure_element->getAttribute('code');
         $error_msg = $failure_element->nodeValue;
         throw new CasValidateException("Error Code " . trim($error_code) . ": " . trim($error_msg));
     }
     $success_elements = $dom->getElementsByTagName("authenticationSuccess");
     if ($success_elements->length === 0) {
         // All responses should have either an authenticationFailure
         // or authenticationSuccess node.
         throw new CasValidateException("XML from CAS server is not valid.");
     }
     // There should only be one success element, grab it and extract username.
     $success_element = $success_elements->item(0);
     $user_element = $success_element->getElementsByTagName("user");
     if ($user_element->length == 0) {
         throw new CasValidateException("No user found in ticket validation response.");
     }
     $username = $user_element->item(0)->nodeValue;
     $this->casHelper->log("Extracted user: {$username}");
     $property_bag = new CasPropertyBag($username);
     // If the server provided any attributes, parse them out into the property
     // bag.
     $attribute_elements = $dom->getElementsByTagName("attributes");
     if ($attribute_elements->length > 0) {
         $property_bag->setAttributes($this->parseAttributes($attribute_elements));
     }
     // Look for a proxy chain, and if it exists, validate it against config.
     $proxy_chain = $success_element->getElementsByTagName("proxy");
     if ($this->casHelper->canBeProxied() && $proxy_chain->length > 0) {
         $this->verifyProxyChain($proxy_chain);
     }
     if ($this->casHelper->isProxy()) {
         // Extract the PGTIOU from the XML.
         $pgt_element = $success_element->getElementsByTagName("proxyGrantingTicket");
         if ($pgt_element->length == 0) {
             throw new CasValidateException("Proxy initialized, but no PGTIOU provided in response.");
         }
         $pgt = $pgt_element->item(0)->nodeValue;
         $this->casHelper->log("Extracted PGT: {$pgt}");
         $property_bag->setPgt($pgt);
     }
     return $property_bag;
 }
 /**
  * Asserts that validation is executed.
  */
 private function assertSuccessfulValidation($returnto, $for_proxy = FALSE)
 {
     $service_params = array();
     if ($returnto) {
         $service_params['returnto'] = 'node/1';
     }
     $validation_data = new CasPropertyBag('testuser');
     if ($for_proxy) {
         $validation_data->setPgt('testpgt');
     }
     // Validation service should be called for that ticket.
     $this->casValidator->expects($this->once())->method('validateTicket')->with($this->equalTo('ST-foobar'), $this->equalTo($service_params))->will($this->returnValue($validation_data));
 }