示例#1
0
 /**
  * {@inheritdoc}
  */
 public function enhance(array $defaults, Request $request)
 {
     if ($this->casHelper->provideCasLogoutOverride($request)) {
         $defaults['_controller'] = '\\Drupal\\cas\\Controller\\LogoutController::logout';
     }
     return $defaults;
 }
示例#2
0
 /**
  * Handles a page request for our forced login route.
  */
 public function forceLogin()
 {
     // TODO: What if CAS is not configured? need to handle that case.
     $query_params = $this->requestStack->getCurrentRequest()->query->all();
     $cas_login_url = $this->casHelper->getServerLoginUrl($query_params);
     $this->casHelper->log("Cas forced login route, redirecting to: {$cas_login_url}");
     return TrustedRedirectResponse::create($cas_login_url, 302);
 }
示例#3
0
 /**
  * Test the logout callback.
  *
  * @covers ::logout
  */
 public function testLogout()
 {
     $logout_controller = $this->getMockBuilder('Drupal\\cas\\Controller\\LogoutController')->setConstructorArgs(array($this->casHelper, $this->requestStack))->setMethods(array('userLogout'))->getMock();
     $this->casHelper->expects($this->once())->method('getServerLogoutUrl')->will($this->returnValue('https://example.com/logout'));
     $logout_controller->expects($this->once())->method('userLogout');
     $response = $logout_controller->logout();
     $this->assertTrue($response->isRedirect('https://example.com/logout'));
 }
示例#4
0
 /**
  * Logs a user out of Drupal, then redirects them to the CAS server logout.
  */
 public function logout()
 {
     // Get the CAS server logout Url.
     $logout_url = $this->casHelper->getServerLogoutUrl($this->requestStack->getCurrentRequest());
     // Log the user out. This invokes hook_user_logout and destroys the
     // session.
     $this->userLogout();
     $this->casHelper->log("Drupal session terminated; redirecting to CAS logout at: {$logout_url}");
     // Redirect the user to the CAS logout screen.
     return new TrustedRedirectResponse($logout_url, 302);
 }
 /**
  * Test the forcedLogin redirect.
  *
  * @covers ::forceLogin
  * @covers ::__construct
  */
 public function testForceLogin()
 {
     $request = $this->getMock('\\Symfony\\Component\\HttpFoundation\\Request');
     $query = $this->getMock('\\Symfony\\Component\\HttpFoundation\\ParameterBag');
     $request->query = $query;
     $this->requestStack->expects($this->once())->method('getCurrentRequest')->will($this->returnValue($request));
     $parameters = array('returnto' => 'node/1', 'foo' => 'bar');
     $query->expects($this->once())->method('all')->will($this->returnValue($parameters));
     $this->casHelper->expects($this->once())->method('getServerLoginUrl')->with($this->equalTo($parameters))->will($this->returnValue('https://example.com'));
     $expected_response = new TrustedRedirectResponse('https://example.com', 302);
     $force_login_controller = new ForceLoginController($this->casHelper, $this->requestStack);
     $response = $force_login_controller->forceLogin();
     $this->assertEquals($expected_response, $response);
 }
示例#6
0
 /**
  * Handles a page request for our forced login route.
  */
 public function forceLogin()
 {
     // TODO: What if CAS is not configured? need to handle that case.
     $query_params = $this->requestStack->getCurrentRequest()->query->all();
     $cas_login_url = $this->casHelper->getServerLoginUrl($query_params);
     $this->casHelper->log("Cas forced login route, redirecting to: {$cas_login_url}");
     // This response is OK to cache, but since the redirect URL is dependent on
     // the configured server settings, we need to add some cache metadata tied
     // to the settings.
     $cacheable_metadata = new CacheableMetadata();
     $cacheable_metadata->addCacheTags(array('config:cas.settings'));
     $response = TrustedRedirectResponse::create($cas_login_url, 302);
     $response->addCacheableDependency($cacheable_metadata);
     return $response;
 }
示例#7
0
 /**
  * Converts a "returnto" query param to a "destination" query param.
  *
  * The original service URL for CAS server may contain a "returnto" query
  * parameter that was placed there to redirect a user to specific page after
  * logging in with CAS.
  *
  * Drupal has a built in mechanism for doing this, by instead using a
  * "destination" parameter in the URL. Anytime there's a RedirectResponse
  * returned, RedirectResponseSubscriber looks for the destination param and
  * will redirect a user there instead.
  *
  * We cannot use this built in method when constructing the service URL,
  * because when we redirect to the CAS server for login, Drupal would see
  * our destination parameter in the URL and redirect there instead of CAS.
  *
  * However, when we redirect the user after a login success / failure,
  * we can then convert it back to a "destination" parameter and let Drupal
  * do it's thing when redirecting.
  *
  * @param Request $request
  *   The Symfony request object.
  */
 private function handleReturnToParameter(Request $request)
 {
     if ($request->query->has('returnto')) {
         $this->casHelper->log("Converting returnto parameter to destination.");
         $request->query->set('destination', $request->query->get('returnto'));
     }
 }
示例#8
0
 /**
  * Proxy authenticates to a target service.
  *
  * Returns cookies from the proxied service in a
  * CookieJar object for use when later accessing resources.
  *
  * @param string $target_service
  *   The service to be proxied.
  *
  * @return \GuzzleHttp\Cookie\CookieJar
  *   A CookieJar object (array storage) containing cookies from the
  *   proxied service.
  *
  * @throws CasProxyException
  */
 public function proxyAuthenticate($target_service)
 {
     // Check to see if we have proxied this application already.
     if (isset($_SESSION['cas_proxy_helper'][$target_service])) {
         $cookies = array();
         foreach ($_SESSION['cas_proxy_helper'][$target_service] as $cookie) {
             $cookies[$cookie['Name']] = $cookie['Value'];
         }
         $domain = $cookie['Domain'];
         $jar = CookieJar::fromArray($cookies, $domain);
         $this->casHelper->log("{$target_service} already proxied. Returning information from session.");
         return $jar;
     }
     if (!($this->casHelper->isProxy() && isset($_SESSION['cas_pgt']))) {
         // We can't perform proxy authentication in this state.
         throw new CasProxyException("Session state not sufficient for proxying.");
     }
     // Make request to CAS server to retrieve a proxy ticket for this service.
     $cas_url = $this->getServerProxyURL($target_service);
     try {
         $this->casHelper->log("Retrieving proxy ticket from: {$cas_url}");
         $response = $this->httpClient->get($cas_url);
         $this->casHelper->log("Received: " . htmlspecialchars($response->getBody()->__toString()));
     } catch (ClientException $e) {
         throw new CasProxyException($e->getMessage());
     }
     $proxy_ticket = $this->parseProxyTicket($response->getBody());
     $this->casHelper->log("Extracted proxy ticket: {$proxy_ticket}");
     // Make request to target service with our new proxy ticket.
     // The target service will validate this ticket against the CAS server
     // and set a cookie that grants authentication for further resource calls.
     $params['ticket'] = $proxy_ticket;
     $service_url = $target_service . "?" . UrlHelper::buildQuery($params);
     $cookie_jar = new CookieJar();
     try {
         $this->casHelper->log("Contacting service: {$service_url}");
         $this->httpClient->get($service_url, ['cookies' => $cookie_jar]);
     } catch (ClientException $e) {
         throw new CasProxyException($e->getMessage());
     }
     // Store in session storage for later reuse.
     $_SESSION['cas_proxy_helper'][$target_service] = $cookie_jar->toArray();
     $this->casHelper->log("Stored cookies from {$target_service} in session.");
     return $cookie_jar;
 }
 /**
  * Route callback for the ProxyGrantingTicket information.
  *
  * This function stores the incoming PGTIOU and pgtId parameters so that
  * the incoming response from the CAS Server can be looked up.
  */
 public function callback()
 {
     // @TODO: Check that request is coming from configured CAS server to avoid
     // filling up the table with bogus pgt values.
     $request = $this->requestStack->getCurrentRequest();
     // Check for both a pgtIou and pgtId parameter. If either is not present,
     // inform CAS Server of an error.
     if (!($request->query->get('pgtId') && $request->query->get('pgtIou'))) {
         $this->casHelper->log("Missing necessary parameters for PGT.");
         return Response::create('Missing necessary parameters', 400);
     } else {
         // Store the pgtIou and pgtId in the database for later use.
         $pgt_id = $request->query->get('pgtId');
         $pgt_iou = $request->query->get('pgtIou');
         $this->storePgtMapping($pgt_iou, $pgt_id);
         $this->casHelper->log("Storing pgtId {$pgt_id} with pgtIou {$pgt_iou}");
         // PGT stored properly, tell CAS Server to proceed.
         return Response::create('OK', 200);
     }
 }
示例#10
0
 /**
  * Tests the enhance() method.
  *
  * @covers ::enhance
  *
  * @dataProvider enhanceDataProvider
  */
 public function testEnhance($config)
 {
     $this->casHelper->expects($this->once())->method('provideCasLogoutOverride')->willReturn($config);
     $enhancer = new CasRouteEnhancer($this->casHelper);
     $defaults = array();
     $defaults = $enhancer->enhance($defaults, $this->request);
     if ($config) {
         $this->assertArraySubset(['_controller' => '\\Drupal\\cas\\Controller\\LogoutController::logout'], $defaults);
     } else {
         $this->assertEmpty($defaults);
     }
 }
示例#11
0
 /**
  * Parse the attributes list from the CAS Server into an array.
  *
  * @param \DOMNodeList $xml_list
  *   An XML element containing attributes.
  *
  * @return array
  *   An associative array of attributes.
  */
 private function parseAttributes($xml_list)
 {
     $attributes = array();
     $node = $xml_list->item(0);
     foreach ($node->childNodes as $child) {
         $name = $child->localName;
         $value = $child->nodeValue;
         $attributes[$name][] = $value;
     }
     $this->casHelper->log("Parsed out attributes: " . print_r($attributes, TRUE));
     return $attributes;
 }
示例#12
0
 /**
  * Check is the current request is from a known list of web crawlers.
  *
  * We don't want to perform any CAS redirects in this case, because crawlers
  * need to be able to index the pages.
  *
  * @return bool
  *   True if the request is coming from a crawler, false otherwise.
  */
 private function isCrawlerRequest()
 {
     $current_request = $this->requestStack->getCurrentRequest();
     if ($current_request->server->get('HTTP_USER_AGENT')) {
         $crawlers = array('Google', 'msnbot', 'Rambler', 'Yahoo', 'AbachoBOT', 'accoona', 'AcoiRobot', 'ASPSeek', 'CrocCrawler', 'Dumbot', 'FAST-WebCrawler', 'GeonaBot', 'Gigabot', 'Lycos', 'MSRBOT', 'Scooter', 'AltaVista', 'IDBot', 'eStyle', 'Scrubby', 'gsa-crawler');
         // Return on the first find.
         foreach ($crawlers as $c) {
             if (stripos($current_request->server->get('HTTP_USER_AGENT'), $c) !== FALSE) {
                 $this->casHelper->log('CasSubscriber ignoring request from suspected crawler "$c"');
                 return TRUE;
             }
         }
     }
     return FALSE;
 }
示例#13
0
 /**
  * Tests that a user is validated and logged in with Drupal acting as proxy.
  *
  * @dataProvider parameterDataProvider
  */
 public function testSuccessfulLoginProxyEnabled($returnto)
 {
     $this->setupRequestParameters($returnto, FALSE, TRUE);
     $this->requestStack->expects($this->once())->method('getCurrentRequest')->will($this->returnValue($this->requestObject));
     if ($returnto) {
         $this->assertDestinationSetFromReturnTo();
     }
     // Cas Helper should indicate Drupal is a proxy.
     $this->casHelper->expects($this->once())->method('isProxy')->will($this->returnValue(TRUE));
     $this->assertSuccessfulValidation($returnto, TRUE);
     $validation_data = new CasPropertyBag('testuser');
     $validation_data->setPgt('testpgt');
     // Login should be called.
     $this->casLogin->expects($this->once())->method('loginToDrupal')->with($this->equalTo($validation_data), $this->equalTo('ST-foobar'));
     // PGT should be saved.
     $this->casHelper->expects($this->once())->method('storePGTSession')->with($this->equalTo('testpgt'));
     $this->assertRedirectedToFrontPageOnHandle();
 }
示例#14
0
 /**
  * Test processing gateway with CHECK_ONCE to make sure SESSION gets set.
  *
  * @covers ::handle
  * @covers ::handleGateway
  */
 public function testHandleGatewayWithCheckOnceSuccess()
 {
     $config_factory = $this->getConfigFactoryStub(array('cas.settings' => array('forced_login.enabled' => TRUE, 'forced_login.paths' => array('<front>'), 'gateway.check_frequency' => CasHelper::CHECK_ONCE, 'gateway.paths' => array('<front>'))));
     $cas_subscriber = $this->getMockBuilder('\\Drupal\\cas\\Subscriber\\CasSubscriber')->setConstructorArgs(array($this->requestStack, $this->routeMatcher, $config_factory, $this->currentUser, $this->conditionManager, $this->casHelper))->setMethods(NULL)->getMock();
     $this->event->expects($this->any())->method('getRequestType')->will($this->returnValue(HttpKernelInterface::MASTER_REQUEST));
     $request_object = $this->getMock('\\Symfony\\Component\\HttpFoundation\\Request');
     $attributes = $this->getMock('\\Symfony\\Component\\HttpFoundation\\ParameterBag');
     $request_object->attributes = $attributes;
     $server = $this->getMock('\\Symfony\\Component\\HttpFoundation\\ServerBag');
     $request_object->server = $server;
     $condition = $this->getMockBuilder('\\Drupal\\Core\\Condition\\ConditionPluginBase')->disableOriginalConstructor()->getMock();
     $this->conditionManager->expects($this->any())->method('createInstance')->with('request_path')->will($this->returnValue($condition));
     $condition->expects($this->any())->method('setConfiguration')->with(array('<front>'));
     $this->conditionManager->expects($this->any())->method('execute')->with($condition)->will($this->onConsecutiveCalls(FALSE, TRUE));
     $request_object->expects($this->once())->method('isMethod')->with('GET')->will($this->returnValue(TRUE));
     $this->requestStack->expects($this->any())->method('getCurrentRequest')->will($this->returnValue($request_object));
     $this->casHelper->expects($this->once())->method('getServerLoginUrl')->will($this->returnValue('https://example.com'));
     $this->event->expects($this->once())->method('setResponse');
     $cas_subscriber->handle($this->event);
     $this->assertArrayHasKey('cas_gateway_checked', $_SESSION);
 }
示例#15
0
 /**
  * Check is the current request is a normal web request from a user.
  *
  * We don't want to perform any CAS redirects for things like cron
  * and drush.
  *
  * @return bool
  *   Whether or not this is a normal request.
  */
 private function isNotNormalRequest()
 {
     $current_request = $this->requestStack->getCurrentRequest();
     if (stristr($current_request->server->get('SCRIPT_FILENAME'), 'xmlrpc.php')) {
         return TRUE;
     }
     if (stristr($current_request->server->get('SCRIPT_FILENAME'), 'cron.php')) {
         $this->casHelper->log("Skip processing requests for cron.");
         return TRUE;
     }
     if ($current_request->server->get('HTTP_USER_AGENT')) {
         $crawlers = array('Google', 'msnbot', 'Rambler', 'Yahoo', 'AbachoBOT', 'accoona', 'AcoiRobot', 'ASPSeek', 'CrocCrawler', 'Dumbot', 'FAST-WebCrawler', 'GeonaBot', 'Gigabot', 'Lycos', 'MSRBOT', 'Scooter', 'AltaVista', 'IDBot', 'eStyle', 'Scrubby', 'gsa-crawler');
         // Return on the first find.
         foreach ($crawlers as $c) {
             if (stripos($current_request->server->get('HTTP_USER_AGENT'), $c) !== FALSE) {
                 $this->casHelper->log("Ignoring request from {$c}");
                 return TRUE;
             }
         }
     }
     return FALSE;
 }
示例#16
0
 /**
  * Test to make sure we don't log when we're not configured to.
  *
  * @covers ::log
  * @covers ::__construct
  */
 public function testLoggingOff()
 {
     $config_factory = $this->getConfigFactoryStub(array('cas.settings' => array('debugging.log' => FALSE)));
     $cas_helper = new CasHelper($config_factory, $this->urlGenerator, $this->connection, $this->loggerFactory, $this->session);
     $this->loggerChannel->expects($this->never())->method('log');
     $cas_helper->log('This is a test, but should not be logged as such.');
 }