Реализация спецификации WS-Security для SOAP в PHP существует?

O1&g

Новичок
Жаль не видел эту тему раньше. Вот здесь (на 2ой странице) реализовано более-менее, я попробовал в своих проектах, все работает.
 

griga

Новичок
Здравствуйте. Скажите пожалуйста, есть какие продвижки в работе над WSE + PHP?
 

griga

Новичок
мне необходимо общаться с вэб сервисом используя шифрование публичным ключом, который дали владельцы этого сервиса. Там у них на серваке приватный ключ. Все это связано с сертификатом
 

MiksIr

miksir@home:~$
Тема то может и некро, но в топах по гугл://php ws security, а решения все еще кустарные. Приделывал тут эквайринг с альфабанком, они хотели ws-security авторизацию. Что нагуглилось, пусть лежит тут.
1. Есть экстеншен, который по ходу умеет кроме ws-security еще блекджек и шлюх. http://wso2.com/products/web-services-framework/php/
Не сложилось у меня с ним секса. Не желая засирать систему (а хрени всякой оно ставит предостаточно) я подорвался собрать rpm, но там были кривые инсталяционные макросы, которые для части файлов игнорируют дестинейшн. Начал патчить мейк-файлы, но быстро надоело и забил. Да и вообще все это для моей задачи выглядело монструозно.
2. Решение нашлось на пхп, немного кустарно написанное - с inline xml, но подобные ему решения написаные всякими ->appendChild показались в данном случае излишеством, да еще и тяжелым.
PHP:
    /**
     * Return header for autentification
     * @return SoapHeader|array
     * @author Roger Veciana i Rovira
     * @licence BSD http://opensource.org/licenses/bsd-license.html
     */
    protected function wssecurity_digest_header() {

        $timestamp = gmdate('Y-m-d\TH:i:s\Z'); //The timestamp. The computer must be on time or the server you are connecting may reject the password digest for security.
        $nonce = mt_rand(); //A random word. The use of rand() may repeat the word if the server is very loaded.
        $passdigest = base64_encode(
            pack('H*', sha1(pack('H*', $nonce) . pack('a*', $timestamp) . pack('a*', $this->password)))
        ); //This is the right way to create the password digest. Using the password directly may work also, but it's not secure to transmit it without encryption. And anyway, at least with axis+wss4j, the nonce and timestamp are mandatory anyway.

        $auth = '
<wsse:Security SOAP-ENV:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
    <wsse:Username>' . $this->username . '</wsse:Username>
    <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest">' . $passdigest . '</wsse:Password>
    <wsse:Nonce>' . base64_encode(pack('H*', $nonce)) . '</wsse:Nonce>
    <wsu:Created xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">' . $timestamp . '</wsu:Created>
   </wsse:UsernameToken>
</wsse:Security>
';

        $authvalues = new SoapVar($auth, XSD_ANYXML);
        return new SoapHeader("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security", $authvalues, true);
    }
Этот метод возвращает SOAP заголовок для авторизации, который нужно передать как $input_headers параметр в вызове __soapCall в стандарной php-шной SoapClient
Типа вот такого
PHP:
    public function __soapCall ($function_name, $arguments, $options = null, $input_headers = null, &$output_headers = null) {
        return parent::__soapCall($function_name, $arguments, $options, $input_headers ? $input_headers : $this->wssecurity_digest_header(), $output_headers);
    }
Правда не заработало с альфабанком. После общения с ихними программистами выяснилось, что они используют PasswordText, а не PasswordDigest. Быстрое чтение стандарта по WS-Security (вполне неплохо написано) привело к упрощенной версии данного метода
PHP:
    /**
     * Return header for autentification
     * @return SoapHeader|array
     */
    protected function wssecurity_text_header() {
        $auth = '
<wsse:Security SOAP-ENV:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<wsse:UsernameToken>
    <wsse:Username>' . $this->username . '</wsse:Username>
    <wsse:Password>' . $this->password . '</wsse:Password>
   </wsse:UsernameToken>
</wsse:Security>
';
        $authvalues = new SoapVar($auth, XSD_ANYXML);
        return new SoapHeader("http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security", $authvalues, true);
    }
Проверено, работает.
 

miha

Новичок
Респект! Тема не дохлая, поскольку постоянно своих клиентов (которые юзают php) отсылаю в эту ветку.
 

Dogan

Новичок
MiksIr
тоже сейчас с Альфой разбираюсь, а вы реализовывали только такой вариант? у них есть ещё вариант с подписью, он то мне и нужен
 

MiksIr

miksir@home:~$
Вариант с подписью не знаю. Мы работаем с РБС 2 у них, это paymentgate который. Возможно у них есть другие платежные шлюзы.
 

Dogan

Новичок
MiksIr
я так понимаю что полноценной поддержки WSSE так и не появилось на php?

возможно ли просто посчитать значения для <ds:SignatureValue> и <ds:DigestValue> ?
 

miha

Новичок
Я как создатель отслеживаю тему, подписан на новые сообщения
 

Pascal9x

Новичок
Ничего не изменилось. Пол года назад искал нормальную либу для пхп для подписывания SOAP-запросов и ничего не нашёл.
В итоге оказалось что быстрее изучить все эти xml-фишки и ручками написать код подписывания запросов.
SOAP это громоздкий монстр который просто ненужен. Вместо него лучше использовать JSON, если конечно есть такая возможность.
 

namesmile

Новичок
Да, тема старая, но по существу ничего не изменилось.Нормальной поддержки WS-Security или библиотеки для ее реализации на php (или не только на php?:rolleyes:) нет :(

У меня попался wsdl с wsHTTPbinding, в котором используется подпись сертификатом x509 + логин/пароль.
Служба поддержки прислала несколько xml конвертов запросов и ответов в порядке их применения.

Собственно, первый конверт запроса из 3:

PHP:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"
            xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
    <s:Header>
        <a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RST/SCT</a:Action>
        <a:MessageID>urn:uuid:b8337de1-9cd0-42c6-a8ab-af440666cf2f</a:MessageID>
        <a:ReplyTo>
            <a:Address>http://www.w3.org/2005/08/addressing/anonymous</a:Address>
        </a:ReplyTo>
        <a:To s:mustUnderstand="1">https://myairops.com/OpisService/AiropsScheduleDataService.svc</a:To>
        <o:Security s:mustUnderstand="1"
                    xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
            <u:Timestamp u:Id="_0">
                <u:Created>2014-12-18T16:57:39.229Z</u:Created>
                <u:Expires>2014-12-18T17:02:39.229Z</u:Expires>
            </u:Timestamp>
            <o:UsernameToken u:Id="uuid-66a9fd12-5846-41a5-8250-17abe6fb1806-11">
                <o:Username>ИМЯ</o:Username>
                <o:Password
                        Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">
                    ПАРОЛЬ
                </o:Password>
            </o:UsernameToken>
        </o:Security>
    </s:Header>
    <s:Body>
        <t:RequestSecurityToken xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
            <t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</t:TokenType>
            <t:RequestType>http://schemas.xmlsoap.org/ws/2005/02/trust/Issue</t:RequestType>
            <t:Entropy>
                <t:BinarySecret u:Id="uuid-dda9572f-36f1-49c1-a0a5-24441199baf0-3"
                                Type="http://schemas.xmlsoap.org/ws/2005/02/trust/Nonce">
                    dfsRtUdCmaNSea66xeIngWNudOhg7HCSWDDLAZNP3Ss=
                </t:BinarySecret>
            </t:Entropy>
            <t:KeySize>256</t:KeySize>
        </t:RequestSecurityToken>
    </s:Body>
</s:Envelope>
и ответ на него:
PHP:
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing"
            xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<s:Header>
    <a:Action s:mustUnderstand="1">http://schemas.xmlsoap.org/ws/2005/02/trust/RSTR/SCT</a:Action>
    <a:RelatesTo>urn:uuid:b8337de1-9cd0-42c6-a8ab-af440666cf2f</a:RelatesTo>
    <o:Security s:mustUnderstand="1"
                xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
        <u:Timestamp u:Id="_0">
            <u:Created>2014-12-18T16:57:22.092Z</u:Created>
            <u:Expires>2014-12-18T17:02:22.092Z</u:Expires>
        </u:Timestamp>
    </o:Security>
</s:Header>
<s:Body>
    <t:RequestSecurityTokenResponse xmlns:t="http://schemas.xmlsoap.org/ws/2005/02/trust">
        <t:TokenType>http://schemas.xmlsoap.org/ws/2005/02/sc/sct</t:TokenType>
        <t:RequestedSecurityToken>
            <c:SecurityContextToken u:Id="uuid-aa470dc5-8178-47bb-a290-2b24ba093ec8-933"
                                    xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
                <c:Identifier>urn:uuid:a1003c5e-8c6b-4dc3-a943-cb4240bdbd54</c:Identifier>
            </c:SecurityContextToken>
        </t:RequestedSecurityToken>
        <t:RequestedAttachedReference>
            <o:SecurityTokenReference
                    xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                <o:Reference ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct"
                             URI="#uuid-aa470dc5-8178-47bb-a290-2b24ba093ec8-933">

                </o:Reference>
            </o:SecurityTokenReference>
        </t:RequestedAttachedReference>
        <t:RequestedUnattachedReference>
            <o:SecurityTokenReference
                    xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
                <o:Reference URI="urn:uuid:a1003c5e-8c6b-4dc3-a943-cb4240bdbd54"
                             ValueType="http://schemas.xmlsoap.org/ws/2005/02/sc/sct"></o:Reference>
            </o:SecurityTokenReference>
        </t:RequestedUnattachedReference>
        <t:RequestedProofToken>
            <t:ComputedKey>http://schemas.xmlsoap.org/ws/2005/02/trust/CK/PSHA1</t:ComputedKey>
        </t:RequestedProofToken>
        <t:Entropy>
            <t:BinarySecret u:Id="uuid-aa470dc5-8178-47bb-a290-2b24ba093ec8-934"
                            Type="http://schemas.xmlsoap.org/ws/2005/02/trust/Nonce">
                SGWZ0t0muG6g0pzz0ba45We0hbKer/sN7IgvmNZJuVE=
            </t:BinarySecret>
        </t:Entropy>
        <t:Lifetime>
            <u:Created>2014-12-18T16:57:22.092Z</u:Created>
            <u:Expires>2014-12-19T07:57:22.092Z</u:Expires>
        </t:Lifetime>
        <t:KeySize>256</t:KeySize>
    </t:RequestSecurityTokenResponse>
</s:Body>
</s:Envelope>
В заголовок нужно добавить Timestamp - время генерации и время окончания действия с разницей в 5 минут. UsernameToken и т.п.

Но как я понял здесь перед вызовом единственного метода, нужно получить BinarySecret, запрос на который отправить в RequestSecurityToken и после этого использовать его для вызова метода?
 

WMix

герр M:)ller
Партнер клуба
а просто по https обратиться, недостаточная защита?
 

namesmile

Новичок
а просто по https обратиться, недостаточная защита?
Судя по всему нет :(
Из службы поддержки ответили, что они тщательно подбирали уровень защиты и не будут его снижать. И прибавили, что похоже никто из их клиентов так и нет реализовал все это на чистом PHP: они используют связку C# + PHP или Java + PHP.

Много копал интернет. Нашел парня по имени Jason Remley в какой-то гугл группе, который решал подобную задачу ранее. Написал ему, его ответ:
No...not with php at least...I eventually gave up and used Java Metro instead...much easier to get going and obviously more compatible with the .Net web services. I wasted weeks on the php stuff....with java I had a functioning protoype in a couple of hours....and most of the work was just getting a socket interface setup so my php program could talk with the java program. WAY easier.
...
My php code runs the java program then uses a socket to pass parameters and whatever web service function I want via a JSON string...the java program talks to the webservice, and parses the xml into java objects...which I convert back into JSON and return to my php program over the socket. Works really well....its sort of like a proxy server for the webservice.
...
There probably much more out there on the subject....but hopefully that'll give you some place to start. Like I said, once I got started with it, it turned out to be really easy....and I had never really written much java before either. Much easier than pulling my hair out over the php code :)

Jason Remley
Сказал, что исходниками не поделится из-за соглашения о приватности, но отправил несколько ссылок, которыми он руководствовался при написании Java программы:

https://jax-ws.java.net/articles/handlers_introduction.html
http://www.middlewareguru.com/mw/?p=688
http://www.javaworld.com/article/2077679/soa/get-a-handle-on-the-jax-ws-api-s-handler-framework.html
http://www.java-tips.org/java-ee-tips/java-api-for-xml-web-services/writing-a-handler-in-jax-ws.html

Так что буду писать Java программку , которая будет отдавать JSON. Спасибо Джейсону за совет. Я с этой штуковиной провозился почти 2 месяца.

Сейчас часть программы готова. Я так и не понял как это все произошло, но к этому wsdl Java подключилась без труда. Теперь осталось сделать, чтобы отдавала JSON.
 

WMix

герр M:)ller
Партнер клуба
да брось ты, все шифруется на уровне консоли, я просто не понимаю зачем, но да за пятерку евро думаю написал бы, нужно задачник смотреть, да спецификацию wsdl..
 
Сверху