Главная
Блог разработчиков phpBB
 
+ 17 предустановленных модов
+ SEO-оптимизация форума
+ авторизация через соц. сети
+ защита от спама

Электронные библиотеки на работе и дома

Anna | 31.05.2014 | нет комментариев

Навеяно статьёй про науку под замком. Правда моя статья не об этом, но тоже про доступ к электронным библиотекам, правда и иного нрава.

Тружусь в западном… не, всё же северном институте, и доводится читать много статей из своей области изысканий. Благо, здесь университетская библиотека подписана на уйма электронных библиотек (увлекательно, сколько это наслаждение стоит… не, не так – сколько мещане наживаются на наших статьях?). По моей тематике таких библиотек три – ACM, IEEE и Springer. А в них – львиная доля того, что мне необходимо. И всё бы здорово, но есть одно НО.

Электронные библиотеки (ЭБ) определяют пользователей, видимо, по IP. Может я не прав, но доступ к ним открыт только если компьютер физически (через витую пару) подключен к сети Института. По крайней мере, на станицах ЭБ значится по чьей подписке я могу скачивать статьи. Довольно только подключиться к сети Института по беспроводной сети, как сразу же ЭБ начинает умолять деньги за статью. Внятное дело, за пределами института я только и вижу только тарифы на чтение труда коллег и своего собственного.

А что если я дома решил поработать (ну это я шучу: кто это сумеет поработать в присутствии трёх сорванцов…) ну либо в командировке мне позарез потребовалось что–то проверить, уточнить, либо легко почитать, в конце–концов (дюже настоящий случай)? В какой–то момент, я решил нужно как–то это дело решать. Здешний админ обрадовал меня только тем, что я не 1-й кто умоляет у него придумать решение как получить доступ к ЭБ удалённо. Без обещаний что–либо сделать. Позднее от сотрудники узнал что есть какое–то решение на общенациональном источнике, но работает оно как–то нестабильно – невзирая не то что сотрудник показала как она подключается к ЭБ через данный источник, у меня почему–то те же действия не привели к желаемому итогу.

Вот тогда и возникло решение сделать всё самому, от того что имеются небольшие навыки программирования PHP и JS. А также тот факт, что есть папки пользователей в локальной сети (из–под которой действует подписка на ЭБ), и в них дозволено размещать PHP–скрипты. Задумка выглядела так:

  • поместить прокси в своей папке на локальном сервере Института,
  • написать растяжение под Google Chrome, Дабы
  • все ссылки ведущие на страницах ЭБ «не туда» (не на PDF статьи) менялись бы «на лету», т.е. всё выглядело бы так как словно нет никакого прокси и статьи открываются так как словно трудишься из внутренней сети Института.

Позже поиска PHP проксей был взят простенький скрипт (благодарности Eric-Sebastien Lachance) передающий все HTTP заголовки (т.е. включая куки пользователя). Правда, его пришлось крайне расширить, Дабы 1) ограничить число доменов к которым дозволено обращаться пользователю, и 2) разрешать пользоваться им только студентам и работникам Института (ну вы понимаете отчего это не может стать доступным для всех желающих…), а для этого проверять залогинен ли пользователь в локальной сети (Интранете, залогиниться туда дозволено удалённо; кстати, данный шаг дозволено опустить, если пользоватся только самому). Для этого в всяком запросе, помимо собственно URL на PDF статьи, должен присутствовать ID его сессии в Интранете. Прокси делает запрос на страницу Интранета, установив необходимый куки (JSESSIONID в моём случае) в переданное значение, и если от Интранета приходит позитивный результат, то исполняет запрос к ЭБ.

Проверка пользователя

function verifyUser($authCookieValue) {
	global $authCheckURL;
	global $authSuccessHTML;
	global $authCookieName;

	$result = false;
	$error = '';

	// create a new cURL resource
	$ch = curl_init();
	if ($ch !== false) {
		// set URL and other appropriate options
		$header = array();
		$header[] = 'Accept: text/html,application/xhtml xml,application/xml;q=0.9,*/*;q=0.8';
		$header[] = 'Accept-Language: en-US,en;q=0.5';
		$header[] = 'Connection: close';
		$header[] = 'DNT: 1';

		curl_setopt($ch, CURLOPT_URL, $authCheckURL);
		curl_setopt($ch, CURLOPT_HEADER, false);
		curl_setopt($ch, CURLOPT_USERAGENT, 'User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0');
		curl_setopt($ch, CURLOPT_COOKIESESSION, true);
		curl_setopt($ch, CURLOPT_COOKIE, $authCookieName.'='.$authCookieValue);
		curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
		curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

		// grab URL and pass it to the browser
		$response = curl_exec($ch);

		if($response === false) {
			$error = curl_error($ch);
		} else {
			$result = strpos($response, $authSuccessHTML) !== false;
		}

		curl_close($ch);
	} else {
		$error = 'cannot initialize cURL';
	}

	return array(
			'succeeded' => $result,
			'error' => $error
	);
}

На стороне пользователя работает растяжение Google Chrome (состоит из 2-х частей – встраиваемый в страницу код, и код с доступом к вкладкам и куки работающий в фоновом режиме), и если URL относится к одной из трёх библиотек, то страница при загрузке сканируется на присутствие определённых элементов которые обязаны быть на всякой странице где есть ссылка на PDF статьи (для всякой ЭБ это, безусловно, различные элементы). Если такие элементы обнаружены, то туда подставляется запрос к прокси с верно сформированной ссылкой на PDF статью. (Поиск того как и из каких из данных на странице верно сформировать ссылку занял достаточно много времени).

Пример для ACM

// proxy config
var PROXY_URL = 'http://university.org/~user/proxy.php?';
var PROXY_URL_QUERY = 'urlForProxy=';
var PROXY_ID_QUERY = 'idForProxy=';

// page search and modification const
var ACM_PDF_LINK_NAME = 'FullTextPDF';
var ACM_ARTICLE_ID_NAME = 'id';
var ACM_PURCHASE_LINK = 'https://dl.acm.org/purchase.cfm';
var ACM_QUERY_URL = 'http://dl.acm.org/ft_gateway.cfm';
var ACM_QUERY = 'id={0}';
var ACM_LINK = '<a name="'   ACM_PDF_LINK_NAME   '" title="FullText PDF" href="{0}" target="_blank"><img src="imagetypes/pdf_logo.gif" alt="PDF" border="0">PDF</a> [proxy]';

// requests to the background page
var REQUEST_AUTH = 'auth';

function setACMLink() {
	var pdfLink = document.getElementsByName(ACM_PDF_LINK_NAME)[0];
	if (!pdfLink) {
		var i, id, param;
		var params = window.location.search.substr(1).split('&');
		for (i = 0; i < params.length; i  ) {
			param = params[i].split('=');
			if (param[0] === ACM_ARTICLE_ID_NAME) {
				id = param[1].indexOf('.') > 0 ? param[1].split('.')[1] : param[1];
				break;
			}
		}

		if (id) {
			var link = PROXY_URL   ACM_QUERY.format(id)   '&'  
				PROXY_URL_QUERY   encodeURIComponent(ACM_QUERY_URL);

			// purchase link is a placeholder for a link to PDF
			var a, container;
			var links = document.getElementsByTagName('a');
			for (i = 0; i < links.length; i  ) {
				a = links[i];
				if (a.href.indexOf(ACM_PURCHASE_LINK) === 0) {
					container = a.parentNode;
					container.innerHTML = ACM_LINK.format('#');
					setClick(container.childNodes[0], link);
					break;
				}
			}
		}
	}
}

function setClick(elem, link) {
	elem.addEventListener('click', function (e) {
		commPort.postMessage({name: REQUEST_AUTH, href: link});
		e.preventDefault();
		return false;
	});
}

При клике на это ссылку к запросу присоединяется значение куки которая содержит ID сессии в Интранете Института.

Добавление идентификатора сессии в Интранете

В фоновом коде:

// config
var AUTH_URL = 'https://university.org/intranet';
var AUTH_COOKIE = 'JSESSIONID';

// const
var REQUEST_AUTH = 'auth';

chrome.runtime.onConnect.addListener(function (port) {
	port.onMessage.addListener(function (request) {
		var answer = {toRequest: request.name};
		if (request.name === REQUEST_AUTH) {	// check the authorization on the select web-site
			answer.href = request.href;
			answer.result = false;
			answer.id = '';
			chrome.cookies.get({url: AUTH_URL, name: AUTH_COOKIE}, function (cookie) {
				if (cookie) {
					answer.result = true;
					answer.id = cookie.value;
				}
				port.postMessage(answer);
			});
		} 
	});
});

Во встроеном в страницу коде:

var commPort = chrome.runtime.connect();
commPort.onMessage.addListener(function (answer) {
	if (answer.toRequest === REQUEST_AUTH) {
		// add an authorization id, and send the request to to the proxy
		window.location = answer.href   '&'   PROXY_ID_QUERY   answer.id;
	} 
});

Правда, для того Дабы открывались статьи на IEEE пришлось много повозиться. Оказывается, для IEEE необходимо открыть всякую страницу на сайте его ЭБ через прокси (в Хроме открывается добавочная вкладка, которая закрывается сразу позже загрузки контента), Дабы получить от него куки с идентификаторами пользователя с подпиской. Плюс пришлось поколдовать с заменой в полученных куки значений domain и path (последнее было необязательным) в PHP, Дабы они могли механически передаваться совместно с запросом на PDF к прокси: приходили они (позже этого добавочного запроса для приобретения идентификаторов) как domain=ieeexplore.ieee.org, а линк на PDF теснее указывал не на .ieeexplore.ieee.org/query, а на university.org/~user/proxy?url= ieeexplore.ieee.org%5Fquery, следственно нужно было править их на domain=.university.org, path=/~user/proxy.

Переделка куки полученых от IEEE

// config
$cookieDomain = '.university.org';
$cookiePath = '/~user';

$headerArray = explode("rn", $response['header']);

$js = '';
foreach ($headerArray as $headerLine) {
	if (strpos($destinationURL, 'ieee.org') !== false) {
		if (strpos($headerLine, 'Set-Cookie: ') !== false) {
			$cookieArray = explode(': ', $headerLine, 2);
			$headerLine = $cookieArray[0].': ';

			$cookieDataArray = explode('; ', $cookieArray[1]);
			$isFirstKey = true;
			$js .= '  document.cookie = "';
			foreach ($cookieDataArray as $cdKey => $cookieData) {
				list($cname, $cvalue) = array_merge(explode('=', $cookieData), array(''));
				if ($cname === 'domain') {
					$cvalue = $cookieDomain;
					$cookieDataArray[$cdKey] = $cname.'='.$cvalue;
				}
				if ($cname === 'path') {
					$cvalue = $cookiePath;
					$cookieDataArray[$cdKey] = $cname.'='.$cvalue;
				}
				$headerLine .= ($isFirstKey ? '' : '; ').$cookieDataArray[$cdKey];
				$js .= ($isFirstKey ? '' : '; ').$cookieDataArray[$cdKey];
				$isFirstKey = false;
			}
			$js .= "";rn";
		}
		header($headerLine);

		if (strlen($js) > 0) {
			echo "rn<script>rn".$js.'</script>'; // insert JS code into the page to set IEEE session and identification cookies
		}
	} else {
		foreach ($headerArray as $headerLine) {
			header($headerLine);
		}
	}
}

Последнее что хочу подметить, так это то это слабые стороны такой реализации:

  • Если поменяется что–то в вёрстке страниц ЭБ, это решение перестанет трудиться. Но пока работает это дюже комфортно: залогинился в Интранете, и трудишься
  • Есть кое–какие задачи с безопасностью: идентификатор сессии передаётся по HTTP, и допустимо его дозволено перехватить. Пока я один использую это решение, риск мне видится нулевым – как преступник узнает что за комплект цифр я передаю в прокси? Впрочем если он изучит растяжение, приобретение доступа к чужому аккаунту в Интранете Института станет делом техники. А HTTPS на директории пользователей на нашем сервере не распространяется… Допустимо, нужно будет применять шифрование идентификатора сессии в растяжении (CryptoJS) и расшифровку на стороне сервера (пока не нашёл, как: буду благодарен за подсказку), так как всё же планирую разослать растяжение коллегам

А вот полный начальный код.

P.S. Если кто–то знает лучшее и такое же комфортное решение, просьба поделиться. Дозволено брать код, пользовать, редактировать, делиться и т.д. Вообще, есть идея это на github залить, и если будут пожелания в комментариях, то так и сделаю.
P.P.S. За код крепко не ругайте — времени огромнее ушло на выяснение какие слать запросы проски (исключительно для ЭБ на IEEE), чем на сам код. Он может также неполным — не неизменно подставлять правилный линк.

Источник: programmingmaster.ru

Оставить комментарий
Форум phpBB, русская поддержка форума phpBB
Рейтинг@Mail.ru 2008 - 2017 © BB3x.ru - русская поддержка форума phpBB