Pull to refresh

Ws-security в SoapUI Pro

Reading time8 min
Views36K
В области разработки различных платежных шлюзов и при решении других интеграционных задач (не думаю, что этим ограничивается область применения данной технологии, но я столкнулся именно в этой области) может встретиться аутентификация в системе согласно спецификации Ws-security (подробное описание в docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0.pdf). В этой статье будет рассмотрен случай доступа к веб-сервисам, аутентификация клиента в которых производится по данной спецификации.

Допустим, вы обменялись с системой (под системой имеется ввиду платежная система или другая организация, предоставляющая доступ к веб-сервисам) двумя сертификатами (один для двустороннего ssl, другой для подписывания сообщений). Для этого системе потребуется от вас два запроса на сертификат. Вам будет необходимо создать две пары «запрос на сертификат-закрытый ключ». Сделать это можно, например, с помощью утилиты openssl (ссылка для скачивания slproweb.com/products/Win32OpenSSL.html). В ней два раза нужно выполнить команду:

openssl req -new -key privkey1.key -out request1.csr

(второй раз privkey2.key и request2.csr соответственно). У вас в результате получились две пары «запрос-ключ» (privkey1.key & request1.csr, privkey2.key & request2.csr). Два запроса на сертификат нужно отправить аналитикам системы, они, в свою очередь, подписав эти запросы и добавив в свои хранилища, отправят вам обратно сертификаты в формате *.crt для доступа к их системе. Пусть первой паре «запрос-закрытый ключ» будет соответствовать сертификат ssl.crt, который будет использоваться для обеспечения двустороннего ssl, второй паре – trust.crt, этот сертификат будет использоваться для подписывания сообщений.
Когда мы получили эти сертификаты, мы можем проверить, доступен ли нам веб-сервис и все ли правильно с сертификатами даже из браузера. Для этого нам нужно добавить пару «закрытый ключ-сертификат» в хранилище ключей (keystore). В браузере будем использовать хранилище формата pkcs12. Его можно создать тем же самым openssl. Команда следующая:

openssl pkcs12 -export -in ssl.crt -inkey privkey1.key -out ssl.p12

Естественно, команду нужно выполнять в директории, в которой находятся файлы сертификата и закрытого ключа (либо прописать их полный путь). Итак, мы получили файл формата *.p12, который содержит в себе пару «закрытый ключ-сертификат» (из первой пары ssl.p12, из второй — trust.p12). Для того, чтобы увидеть какие элементы присутствуют в хранилище, можно воспользоваться стандартными командами openssl, но лучше применить программу Keystore Explorer (http://keystore-explorer.sourceforge.net/). В ней же можно задать необходимые алиасы для идентификации пар «сертификат-закрытый ключ», если их в хранилище несколько.

Разработка клиента на языке программирования (мы реализовывали на Java и C#), обменивающегося сообщениями с веб-сервисами и реализующего аутентификацию клиентов в системе в данной статье не рассматривается. В этот момент было бы хорошо до начала разработки проверить каким-нибудь инструментом, нет ли какого-нибудь подвоха в сертификатах и будет ли работать подписывание должным образом.
Для проверки аутентификации и подписывания будем использовать SoapUI Pro версии 4.5.1. Вначале нам нужно добавить в настройки SoapUI SSL-сертификат для обеспечения защищенного канала с веб-сервисом. В этой версии программы это делается следующим образом: File -> Preferences -> SSL Settings. У меня стоит английская версия, поэтому все термины на английском. В поле KeyStore указываем путь к хранилищу ssl.p12. В поле KeyStore Password указываем пароль, который мы задавали при создании хранилища. Создать хранилище без пароля не получится и этого делать нельзя, потому что он содержит закрытый ключ. Нажимаем ОК, на этом настройка SSL завершена.

После этого нам необходимо настроить так называемый usernametoken, его подпись и подпись тела сообщения. Подписывание и наличие usernametoken определяются на сервере требованиями безопасности и наличием аутентифкации по токену. О подписывании в SoapUI достаточно подробно написано на сайте самого SoapUI: www.soapui.org/SOAP-and-WSDL/applying-ws-security.html. Где-то повторяясь, где-то добавляя свое, я продолжу свою статью.

I) Добавляем хранилище в нашу пару «ключ-сертификат» для создания подписей:



Если проверять на правильность подписи приходящих к нам сообщений мы не собираемся, то в Truststores добавлять ничего не нужно. Здесь мы добавили хранилище trust.p12, так как именно оно создавалось для подписывания сообщений. Также допустимо использование хранилищ других форматов, например, *.jks (java keystore).

II) Создаем конфигурацию для применения к SOAP-запросам при отправке на веб-сервис. Для этого во вкладке Outgoing WS-Security Configurations нажимаем добавить новую WSS-конфигурацию. Называем ее outgoing.



III) В конфигурацию добавляем usernametoken.
Если в качестве идентификатора клиента служит его номер телефона, то прописываем номер телефона, одним словом, логин клиента в системе. Если имеется пароль, то нужно выбрать Password Type -> PasswordDigest, чтобы он отображался в сообщении в зашифрованном виде.



IV) Так как предполагалось, что мы подписываем две части нашего SOAP-сообщения (usernametoken и Body), то нам нужно создать две подписи. Для этого наряду с Username добавляем два элемента Signature.

V) Первая подпись предназначена для подписывания UsernameToken:



Прописываем все настройки как на рисунке (настройки в вашем случае могут отличаться), пароль от хранилища, в Parts прописываем ту часть нашего SOAP-сообщения, которое мы собираемся подписать. Namespace для UsernameToken:
docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd

VI) Отличие второй подписи (для части Body SOAP-сообщения) от первой только в части Parts:



Namespace для Body:
schemas.xmlsoap.org/soap/envelope
На этом настройка аутентификации и подписывание завершены. Осталось сформировать в SoapUI SOAP-сообщение и выбрать для него необходимую конфигурацию (в части outgoing wss):



При отправке сообщения SoapUI сам добавит usernametoken и две подписи. Для того, чтобы увидеть какое сообщение отправляется можно добавить в endpoint название сервиса posttestserver.com/post.php, и в ответе будет содержаться ссылка на страницу с нашим запросом. Исходный SOAP-запрос может представлять из себя что-то подобное:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
   <soapenv:Header/>
   <soapenv:Body wsu:Id="id-17" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
      <findSomething/>
   </soapenv:Body>
</soapenv:Envelope> 


Подписанный запрос будет выглядеть подобным образом:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
	<soapenv:Header>
		<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
			<ds:Signature Id="SIG-21" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
				<ds:SignedInfo>
					<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
					<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
					<ds:Reference URI="#id-17">
						<ds:Transforms>
							<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
								<InclusiveNamespaces PrefixList="" xmlns="http://www.w3.org/2001/10/xml-exc-c14n#"/>
							</ds:Transform>
						</ds:Transforms>
						<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
						<ds:DigestValue>wU/JToBU67+gCBtfb2+gYL1w9zY=</ds:DigestValue>
					</ds:Reference>
				</ds:SignedInfo>
				<ds:SignatureValue>Ez94qqmkV642l3jIy+8PS8lozO+VtEbMZvYZv3inNV4QCZBsRCmQ9IvGcUhfMXnDlqukXaa+zRwr
dW8tVOW9vkc9DVgzeFGMSREvP2BUuqB6HzZKCGeec3Jihlc59EyuHwyiz5+18jObuyD18Mtb7T90
7adQsDVSBmQGLydX/tfptopmykYfUpRYTh0sMCcRH7J4B51RrecBs6rK9GJEslWTeW2tGgxpxQJ4
Y690rzkrR6AT6h7t4HBD6JltQUi9xwsjpnQ0j0ReSiK+jNNf99pBl7iiEPc9Kzrc8vNKRacbTfm4
/EE9xP6qu61hBxFQpmpWTRt+SmvVCkDOkBAGew==</ds:SignatureValue>
				<ds:KeyInfo Id="KI-7D1A45FAAA5C9F47FD138788868310035">
					<wsse:SecurityTokenReference wsu:Id="STR-7D1A45FAAA5C9F47FD138788868310036">
						<wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">lPhvPtZSH+7TfXO2TMEIe0jlDQw=</wsse:KeyIdentifier>
					</wsse:SecurityTokenReference>
				</ds:KeyInfo>
			</ds:Signature>
			<ds:Signature Id="SIG-20" xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
				<ds:SignedInfo>
					<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
					<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
					<ds:Reference URI="#UsernameToken-19">
						<ds:Transforms>
							<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
								<InclusiveNamespaces PrefixList="soapenv" xmlns="http://www.w3.org/2001/10/xml-exc-c14n#"/>
							</ds:Transform>
						</ds:Transforms>
						<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
						<ds:DigestValue>Bbt473ZLc41VKtiEZbMI+q+sFZY=</ds:DigestValue>
					</ds:Reference>
				</ds:SignedInfo>
				<ds:SignatureValue>F/K6Lgw3P40hFo1ifYY894V5HpVCvns8P4mbeR9pZfTVg4MH/hZf0+KKfKnURTTwS8Rw9MlOM9gG
rwkk0hEANxraZHcMIuopWJlvf6sBkykyVSgrAFCHhqjVdAb7bacv7P6U4wHjY1PNRFWMYSUavewq
KN08xp80lH30SEMIZznKX6pUuRBllEUTIvRMaR62z1GcNkLWLf5hadUGbv8Qdssj1BL5SY2zin3d
hAPFlobMzMUVh019h4Eg0ljWrtFAhHZMOJouZKVYr6ldsPaMiIm9QYTArPoh4fH/rdIIiDT6SVHr
e8v0fdywWnapepGyFDJa1ltUXw+JrqBm579PsQ==</ds:SignatureValue>
				<ds:KeyInfo Id="KI-7D1A45FAAA5C9F47FD138788868306932">
					<wsse:SecurityTokenReference wsu:Id="STR-7D1A45FAAA5C9F47FD138788868306933">
						<wsse:KeyIdentifier EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">lPhvPtZSH+7TfXO2TMEIe0jlDQw=</wsse:KeyIdentifier>
					</wsse:SecurityTokenReference>
				</ds:KeyInfo>
			</ds:Signature>
			<wsse:UsernameToken wsu:Id="UsernameToken-19">
				<wsse:Username>9035153503</wsse:Username>
				<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">sTK/zTQP+BthB9Ag9uYsPXCn2Q8=</wsse:Password>
				<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">wuPL8u2jN8p3T4u0oAZTiQ==</wsse:Nonce>
				<wsu:Created>2013-12-24T12:38:03.065Z</wsu:Created>
			</wsse:UsernameToken>
		</wsse:Security>
	</soapenv:Header>
	<soapenv:Body wsu:Id="id-17" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
		<findAllPersonalAccounts/>
	</soapenv:Body>
</soapenv:Envelope>


Как видно, имеем две подписи <Signature ...>... и один <wsse:UsernameToken ...>...</wsse:UsernameToken>. Первая подпись относится к Body, что видно из <ds:Reference URI="#id-17">, так как <soapenv:Body wsu:Id=«id-17» ..., вторая — к UsernameToken, так как во второй подписи URI="#UsernameToken-19".
Tags:
Hubs:
+1
Comments0

Articles