barbitoff programmer`s blog

Здесь я публикую заметки из программерской жизни: грабли, на которые мне случилось наступить, проблемы, для которых было найдено элегантное (или не очень) решение, а также все, с чем мне пришлось столкнуться и чем хотелось бы поделиться =)
PS Если хотите меня поблагодарить - на странице есть 3 места, чтобы это сделать =)

пятница, 11 сентября 2015 г.

AvastVBoxSVC.exe и самопроизвольный выход Windows из ждущего режима

Снова к вопросу о самопроизвольном выходе винды и ждущего режима. Вывод "powercfg -lastwake" указал на некий AvastVBoxSVC.exe, что очевидно является частью антивируса avast! Для того, чтобы этот exe-шник перестал будить компьютер, нужно зайти в Панель управления -> Программы и компоненты, найти там аваст, нажать "Изменить", и удалить "Безопасные виртуальные машины" (если, конечно, этот компонента аваста Вам реально не нужен).

четверг, 10 сентября 2015 г.

YouTube Data API v3: ошибка "YouTubeSignUpRequired" при попытке загрузки видео

Проблема

Пытаюсь загрузить видео на Youtube с использованием YouTube Data API v3 (пока что просто с помощью curl), получаю ответ:
< HTTP/1.1 401 Unauthorized
< Vary: X-Origin
< WWW-Authenticate: Bearer realm="https://accounts.google.com/", error=invalid_token
< Content-Type: application/json; charset=UTF-8
< Date: Thu, 10 Sep 2015 16:57:36 GMT
< Expires: Thu, 10 Sep 2015 16:57:36 GMT
< Cache-Control: private, max-age=0
< X-Content-Type-Options: nosniff
< X-Frame-Options: SAMEORIGIN
< X-XSS-Protection: 1; mode=block
< Server: GSE
< Alternate-Protocol: 443:quic,p=1
< Alt-Svc: quic=":443"; p="1"; ma=604800
< Accept-Ranges: none
< Vary: Origin,Accept-Encoding
< Transfer-Encoding: chunked
<
{
 "error": {
  "errors": [
   {
    "domain": "youtube.header",
    "reason": "youtubeSignupRequired",
    "message": "Unauthorized",
    "locationType": "header",
    "location": "Authorization"
   }
  ],
  "code": 401,
  "message": "Unauthorized"
 }
}
При этом с тем же самым токеном другие операции (получение списка подписок, получение списка видео и пр.) работают без проблем, т.е. проблема явно не в токене. 

Решение

У пользователя, которому я хочу загрузить новое видео, еще не создан свой канал. Идем на Youtube через браузер, заходим в "Мой канал", Youtube предлагает создать канал. Соглашаемся. Пробуем еще раз загрузить видео через Data API - ошибка ушла.

среда, 9 сентября 2015 г.

JCP + ruToken: ошибка "java.io.IOException: Can't connect to Aktiv Co. ruToken 0"

Проблема

Используется JCP + ruToken для вычисления ЭЦП. При попытке получить ключ с токена падает ошибка:
Caused by: java.security.UnrecoverableKeyException: Can't connect to Aktiv Co. ruToken 0
at ru.CryptoPro.JCP.KeyStore.s.e(Unknown Source)
at ru.CryptoPro.JCP.KeyStore.ContainerStore.engineGetKey(Unknown Source)
at ru.CryptoPro.JCP.KeyStore.JCPKeyStore.engineGetKey(Unknown Source)
at java.security.KeyStore.getKey(KeyStore.java:792)
...
Caused by: java.io.IOException: Can't connect to Aktiv Co. ruToken 0
at rtjlib.JCP.RutokenReader.lock(Unknown Source)
at ru.CryptoPro.JCP.KeyStore.j.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at ru.CryptoPro.JCP.KeyStore.ContainerStore.a(Unknown Source)
Решение

Текст ошибки не особо содержателен, и по нему совершенно неочевидно, в чем именно проблема. Из того же JCP-шного ControlPane я великолепно вижу Aktiv Co. ruToken 0, включая ключ и сертификат на нем.
Декомпилируем rtjlib.JCP.RutokenReader (rtjlib.jar в jre/lib/ext того JDK, который используется для подписывания). Там IOException с таким текстом кидается в 2 местах, и если в одном он кидается просто в коде после неудачного коннекта, то вот во втором применен замечательный подход "проглатывания исключения":
try
    {
      arrayOfByte = nativeWinJavaReader.getAtr(str, "T=0|T=1");
    }
    catch (Exception localException1)
    {
      throw new IOException("Can't connect to " + str);
    }
Добавляем в бросаемое исключение исходный localException1:
    try
    {
      arrayOfByte = nativeWinJavaReader.getAtr(str, "T=0|T=1");
    }
    catch (Exception localException1)
    {
      throw new IOException("Can't connect to " + str, localException1);
    }
Перекомпилируем класс RutokenReader, подкладываем в целевой JDK. Получаем более развернутую ошибку:
Caused by: java.io.IOException: Can't connect to Aktiv Co. ruToken 0
at rtjlib.JCP.RutokenReader.lock(RutokenReader.java:38)
at ru.CryptoPro.JCP.KeyStore.j.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at ru.CryptoPro.JCP.KeyStore.ContainerStore.a(Unknown Source)
... 25 more
Caused by: java.lang.Exception: Establish context failed with 0x8010001d
at rtjlib.nativeAPI.SCardEstablishContext(Native Method)
at rtjlib.readerImpl.nativeWinJavaReader.getAtr(Unknown Source)
at rtjlib.JCP.RutokenReader.lock(RutokenReader.java:34)
... 28 more
Гуглим код 0x8010001d, узнаем, что расшифровывается он как "SCARD_E_NO_SERVICE - "The Smart card resource manager is not running." (http://blogs.msdn.com/b/alejacma/archive/2011/05/19/scardestablishcontext-fails-with-scard-e-no-service-error.aspx). Гугл же подсказывает и возможную причину: ошибка может быть вызвана нехваткой прав к событию "Global\Microsoft Smart Card Resource Manager Started". На это событие есть права только у интерактивных пользователей, SYSTEM и LOCAL SERVICE. В моем же случае ошибка падала в службе, запускающейся из-под обычного пользователя (но т.к. вход не интерактивный - прав не хватало). Запустили целевую программу в интерактивном режиме (из командной строки) вместо запуска в качестве службы - ошибка ушла. Пока такое решение устроило.

КриптоПРО JCP XMLDSig: java.lang.ClassCastException: content[0] is not a valid X509Data type

При попытки подписывания XML-документа с помощью КриптоПРО JCP падает ошибка:
java.lang.ClassCastException: content[0] is not a valid X509Data type
at ru.CryptoPro.JCPxml.dsig.internal.dom.DOMX509Data.<init>(DOMX509Data.java:68)
at ru.CryptoPro.JCPxml.dsig.internal.dom.DOMKeyInfoFactory.newX509Data(DOMKeyInfoFactory.java:88)
...
Причина - в моем случае был неверно указан keyAlias.

понедельник, 7 сентября 2015 г.

Maven: включение в OSGI-бандл распакованных зависимостей

Задача

Распаковать в собираемый OSGI-бандл некоторые зависимости.

Решение

У maven-bundle-plugin есть инструкция "Embed-Dependency", однако она включает указанные зависимости не распаковывая, т.е. кладет jar-ник внутрь jar-ника. Поэтому приходится использовать комбинацию плагина maven-dependency-plugin и инструкцию "Include-Resource" плагина maven-bundle-plugin:
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <version>2.10</version>
        <executions>
          <execution>
            <id>unpack-dependencies</id>
            <phase>package</phase>
            <goals>
              <goal>unpack-dependencies</goal>
            </goals>
            <configuration>
              <includeArtifactIds>saaj-impl,stax-ex,stax-api,mimepull</includeArtifactIds>
              <excludes>META-INF/**</excludes>
              <outputDirectory>${project.build.directory}/depsToPackIntoBundle</outputDirectory>
            </configuration>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <version>2.5.4</version>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Bundle-SymbolicName>**</Bundle-SymbolicName>
            <Bundle-Name>***</Bundle-Name>
            <Export-Package>***</Export-Package>
            <Fragment-Host>***</Fragment-Host>
            <Import-Package>***</Import-Package>
            <Private-Package>***</Private-Package>
            <Include-Resource>${project.build.directory}/depsToPackIntoBundle</Include-Resource>
          </instructions>        
        </configuration>
      </plugin>
В данном примере зависимости saaj-impl,stax-ex,stax-api,mimepul будут запакованы в OSGI-бандл, за исключением их директорий META-INF.

Настройки log4j для отладки формирования и валидации XMLDSig средствами КриптоПро JCP

log4j.logger.org.jcp.xml.dsig.internal=DEBUG
log4j.logger.com.sun.org.apache.xml.internal.security=DEBUG
log4j.logger.ru.CryptoPro.JCPxml.dsig.internal=DEBUG
log4j.logger.ru.CryptoPro.JCPxml.dsig.internal.dom=DEBUG
log4j.logger.ru.CryptoPro.JCP=DEBUG

Windows: как узнать причину выхода компьютера из ждущего режима

Столкнулся с достаточно раздражающей проблемой: домашний комп самопроизвольно выходит из ждущего режима. Встал вопрос: кто именно в этом виноват? И тут на помощь приходит powercfg:
powercfg -lastwake
покажет, кто разбудил ПК. 

воскресенье, 6 сентября 2015 г.

maven-bundle-plugin и включение в bundle классов, которые не экспортируются и не используются явно экспортируемыми классами

Проблема

Есть maven-проект, использующий maven-bundle-plugin для сборки OSGI-бандла. В этом проекте есть некий класс. Он не принадлежит экспортируемым из бандла пакетам, и явно не используется никаким экспортируемыми из бандла классами. В таком случае maven-bundle-plugin решает, что класс в бандле не нужен, и не включает его в бандл. Задача - включить класс в бандл.

Решение

Для этого пакет класса необходимо включить в Private-Package-блок конфигурации плагина:
      <plugin>
        <groupId>org.apache.felix</groupId>
        <artifactId>maven-bundle-plugin</artifactId>
        <version>1.4.0</version>
        <extensions>true</extensions>
        <configuration>
          <instructions>
            <Bundle-SymbolicName>***</Bundle-SymbolicName>
            <Bundle-Name>***</Bundle-Name>
            <Export-Package>some.public.package</Export-Package>
            <Fragment-Host>***</Fragment-Host>
            <Import-Package>org.apache.ws.security.message,org.apache.axis2.saaj,*; resolution:=optional</Import-Package>
            <Private-Package>some.private.package</Private-Package>          </instructions>        
        </configuration>
      </plugin>

суббота, 5 сентября 2015 г.

WSS4J: ошибка "SOAP Envelope can not have children other than SOAP Header and Body" при попытке добавить security-заголовок

Проблема

Пытаюсь добавить security-заголовок в имеющееся SOAP-сообщение вызовом org.apache.ws.security.message.WSSecHeader.insertSecurityHeader(). Получаю ошибку:
org.apache.axiom.soap.SOAPProcessingException: SOAP Envelope can not have children other than SOAP Header and Body at org.apache.axiom.soap.impl.dom.SOAPEnvelopeImpl.checkChild(SOAPEnvelopeImpl.java:110)
at org.apache.axiom.soap.impl.dom.SOAPEnvelopeImpl.insertBefore(SOAPEnvelopeImpl.java:164)
at org.apache.ws.security.util.WSSecurityUtil.prependChildElement(WSSecurityUtil.java:646)
at org.apache.ws.security.util.WSSecurityUtil.findWsseSecurityHeaderBlock(WSSecurityUtil.java:722)
at org.apache.ws.security.message.WSSecHeader.insertSecurityHeader(WSSecHeader.java:145)
at ru.croc.security.jcp.JCPSigner.sign(JCPSigner.java:63)
... 26 more
Решение

WSS4J почему-то так странно реагирует на отсутствие блока <soapenv:Header/> в SOAP-конверте. Если его туда добавить (пусть даже пустым) перед вызовом insertSecurityHeader - ошибка пропадает.

Ошибка компиляции "package com.sun.org.apache.xml.internal.security does not exist"

Проблема

При сборке проекта с помощью maven возникает ошибка:
package com.sun.org.apache.xml.internal.security does not exist

Решение

Добавить зависимость в pom.xml:
<dependency>
  <groupId>com.sun.xml.security</groupId>
  <artifactId>xml-security-impl</artifactId>
  <version>1.0</version>
  <scope>provided</scope>
</dependency>

пятница, 4 сентября 2015 г.

WSO2 ESB 4.8.1: "java.lang.RuntimeException: Incorrect inclusion value: -1" при подписывании исходящего SOAP-запроса

Проблема

На WSO2 ESB 4.8.1 есть endoint с включенной безопасностью, для него указана некая policy. Безопасность в ней описана в соответствии со стандартом WS-SecurityPolicy 1.1 (http://specs.xmlsoap.org/ws/2005/07/securitypolicy/ws-securitypolicy.pdf), о чем говорит пространство имен http://schemas.xmlsoap.org/ws/2005/07/securitypolicy. При попытке использовать этот endpoint для отправки запроса возникает ошибка:

org.apache.synapse.SynapseException: Unexpected error during sending message out
        at org.apache.synapse.core.axis2.Axis2Sender.handleException(Axis2Sender.java:172)
        at org.apache.synapse.core.axis2.Axis2Sender.sendOn(Axis2Sender.java:71)
        at org.apache.synapse.core.axis2.Axis2SynapseEnvironment.send(Axis2SynapseEnvironment.java:338)
        at org.apache.synapse.endpoints.AbstractEndpoint.send(AbstractEndpoint.java:333)
        at org.apache.synapse.endpoints.AddressEndpoint.send(AddressEndpoint.java:59)
        ...
        at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:77)
        at org.apache.synapse.mediators.AbstractListMediator.mediate(AbstractListMediator.java:47)
        at org.apache.synapse.mediators.base.SequenceMediator.mediate(SequenceMediator.java:131)
        at org.apache.synapse.core.axis2.ProxyServiceMessageReceiver.receive(ProxyServiceMessageReceiver.java:166)
        at org.apache.axis2.engine.AxisEngine.receive(AxisEngine.java:180)
        ...
        at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.RuntimeException: Incorrect inclusion value: -1
        at org.apache.ws.secpolicy.model.Token.setInclusion(Token.java:56)
        at org.apache.ws.secpolicy11.builders.X509TokenBuilder.build(X509TokenBuilder.java:61)
        at org.apache.neethi.AssertionBuilderFactory.build(AssertionBuilderFactory.java:99)
        at org.apache.neethi.PolicyEngine.processOperationElement(PolicyEngine.java:225)
        at org.apache.neethi.PolicyEngine.getPolicyOperator(PolicyEngine.java:154)
        at org.apache.neethi.PolicyEngine.getPolicy(PolicyEngine.java:126)
        at org.apache.ws.secpolicy11.builders.InitiatorTokenBuilder.build(InitiatorTokenBuilder.java:40)
        at org.apache.neethi.AssertionBuilderFactory.build(AssertionBuilderFactory.java:99)
        ...
        at org.apache.neethi.PolicyEngine.getPolicy(PolicyEngine.java:126)
        at org.apache.synapse.util.MessageHelper.getPolicy(MessageHelper.java:522)
        at org.apache.synapse.core.axis2.Axis2FlexibleMEPClient.send(Axis2FlexibleMEPClient.java:404)
        at org.apache.synapse.core.axis2.Axis2Sender.sendOn(Axis2Sender.java:59)
        ... 25 more

Причина

В данном случае причина была в том, что в указанной для endpoint'а policy способ включения токена был указан как:
sp:IncludeToken="http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/IncludeToken/Always"
Данный URL соответствует спецификации WS-SecutiryPolicy 1.2 (http://docs.oasis-open.org/ws-sx/ws-securitypolicy/200702/ws-securitypolicy-1.2-spec-os.doc), тогда как для 1.1 он должен иметь следующий вид:
sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/Always"