В YESIA ПРОЦЕСС ИНТЕГРАЦИИ YESIA JAVA И ОБРАБОТКИ CONNECTION EXCEPTIONS ПРИ ПОЛУЧЕНИИ ТОКЕНА ДОСТУПА МОЖЕТ БЫТЬ ЛЕГКО РЕАЛИЗОВАН ПУТЕМ ОТПРАВКИ ЗАПРОСА POST

Я так понял что pkcs7 хранит в себе сертификат, и просто этим сертификатом проверяешь эту подпись(то есть себя ж), возможно я что-то я понял не так.
Вот код:

   public boolean verify(byte[] data) {
    try {
        CMSSignedData cmsSignedData = new CMSSignedData(data);
        // получаем список сертификатов, которые содержатся в файле
        Store<X509CertificateHolder> certs = cmsSignedData.getCertificates();
        // p7s файл может содержать данные, которые были подписаны, то есть ваш pdf файл
        byte[] content = (byte[]) cmsSignedData.getSignedContent().getContent();
        // проходимся по списку подписей, обычно одна подпись, но стандарт поддерживает множество подписей

        for (SignerInformation si : cmsSignedData.getSignerInfos()) {
            // список всех атрибутов, подписанных вместе с файлом
            AttributeTable signedAttributes = si.getSignedAttributes();
            // атрибут с именем
            Attribute attrSurname = signedAttributes.get(new ASN1ObjectIdentifier("2.5.4.4"));
            // атрибут с именем 2
            Attribute attrGivenName = signedAttributes.get(new ASN1ObjectIdentifier("2.5.4.42"));
            // атрибут с датой подписи
            Attribute attrSigningTime = signedAttributes.get(new ASN1ObjectIdentifier("1.2.840.113549.1.9.5"));
            // выводим дату подписи
            System.out.println(attrSigningTime.getAttributeValues()[0].toString());

            // возможно некоторые атрибуты не были частью подписи, формат поддерживает и такие
            //AttributeTable unsignedAttributes = si.getUnsignedAttributes();

            // получаем идентификатор сертификата, которым подписаны данные
            SignerId signerId = si.getSID();
            // ищем сертификат в коллекции по идентификатору
            Collection certCollection = certs.getMatches(signerId);
            // выбираем первый сертификат, здесь не должно быть больше одного
            Iterator certIt = certCollection.iterator();
            X509CertificateHolder certHolder = (X509CertificateHolder) certIt.next();
            // создаем Verifier на основании сертификата, Verifier использует публичный ключ сертификата
            SignerInformationVerifier verifier = new JcaSimpleSignerInfoVerifierBuilder().build(certHolder);
            // проверяем подпись
            return si.verify(verifier);
        }
    } catch (CertificateException | OperatorCreationException | CMSException e) {
        logger.error(e);
    }
    return false;
}
  
  
    byte[] data = Base64.getUrlDecoder().decode(a);
  
  

Привет. Помогите пожалуйста с получением маркера доступа к данным есиа. Авторизационный код получил. Нужно сделать post запрос на тестовую среду для получения токеда доступа. Вот мой код:

   public void getNewToken(String code, String state, String scope, Token token, boolean byRefresh)
        throws OAuthSystemException, OAuthProblemException, JsonException {
    if (state.equals(this.state.getStateAuthorize())) {
        String timestamp = timestampUtil.generateTimestamp();
        String clientSecret = certificateUtil.getUrlSafeSign(
                scope + timestamp +
                        rpguConfig.getClientID() + this.state.generateStateToken()
        );
        GrantType grantType;
        if (byRefresh) {
            grantType = GrantType.REFRESH_TOKEN;
        } else {
            grantType = GrantType.AUTHORIZATION_CODE;
        }
        OAuthClientRequest requestToEsia = OAuthClientRequest
                .tokenLocation(esiaConfig.getEsiaTokenPoint())
                .setClientId(rpguConfig.getClientID())
                .setRedirectURI(rpguConfig.getRedirectUrl())
                .setScope(scope)
                .setCode(code)
                .setGrantType(grantType)
                .setClientSecret(clientSecret)
                .setParameter("state", this.state.getStateToken())
                .setParameter("token_type", rpguConfig.getTokenType())
                .setParameter("timestamp", timestamp)
                .setParameter("access_type", rpguConfig.getAccessType())
                .buildBodyMessage();

        OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient());

        //OAuthAccessTokenResponse response = oAuthClient.accessToken(requestToEsia);

        OAuthJSONAccessTokenResponse oauthResponse = oAuthClient.accessToken
                (requestToEsia, OAuth.HttpMethod.POST, OAuthJSONAccessTokenResponse.class);



        if (!inspectorToken.checkToken(oauthResponse.getAccessToken())) {
            parserTokenData.parseTokenData(oauthResponse, token); //парсим данные токена
        }
    }
}
  
  

Но при выполнении метода по получению токена – oAuthClient.accessToken выбрасывает ошибку такую:

    org.apache.oltu.oauth2.common.exception.OAuthSystemException: java.net.ConnectException: Connection timed out: connect
at org.apache.oltu.oauth2.client.URLConnectionClient.execute(URLConnectionClient.java:108)
at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:65)
at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:55)
at org.apache.oltu.oauth2.client.OAuthClient.accessToken(OAuthClient.java:71)
at controller.server.esia.AuthorizationServer.getNewToken(AuthorizationServer.java:140)
at service.token.TokenService.getNewTokenByScope(TokenService.java:48)
at web.controller.EsiaController.getAccessCode(EsiaController.java:78)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:220)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:134)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:116)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:861)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:650)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:803)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:790)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1459)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748) ....
  
  

Если пройти по трейсу и посмотреть вглубь всех вызывающих методов то ошибка вываливается при конекте(получение стрима) объекта HttpСlient. В документации сказано что нужно отправлять запросы на: https://esia-portal1.test.gosuslugi.ru/aas/oauth2/te

Читайте также:  Справка о заработке для расчета пособий новый

В чем может быть ошибка? Почему к нему нет доступа?

Возможно кому-то приходилось проводить интеграцию с данным сервисом ЕСИА
. Вопрос возникает в формировании сигнатуры к запросу, т.к. используется протокол SSO SAML
: после формирования запроса на аутентификацию требуется поместить в GET-запрос
ряд параметров: SamlAuth
, AlgSig
, relayState
и Signature
.

  • Вопрос 1: Что такое relayState
    и как оно формируется?

задан 24 июл 2015 в 6:49

dzrock's user avatar

16 бронзовых знаков

Рекомендую копать в сторону spring-saml, у меня оно отлично привинтилось.
Приложу свой конфиг saml-security.xml

   <?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:security="http://www.springframework.org/schema/security"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
                       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">

<bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy">
    <security:filter-chain-map request-matcher="ant">
        <security:filter-chain pattern="/user/saml/login/**" filters="samlEntryPoint"/>
        <security:filter-chain pattern="/user/saml/authnrequestresponselistener/**"
                               filters="samlWebSSOProcessingFilter"/>
    </security:filter-chain-map>
</bean>

<!-- Handler deciding where to redirect user after successful login -->
<bean id="successRedirectHandler"
      class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
    <property name="defaultTargetUrl" value="/user/login/esia/"/>
</bean>

<!-- Register authentication manager with SAML provider -->
<!--<security:authentication-manager alias="samlAuthenticationManager">-->
    <!--<security:authentication-provider ref="samlAuthenticationProvider"/>-->
<!--</security:authentication-manager>-->

<bean id="samlAuthenticationManager" class="org.springframework.security.authentication.ProviderManager">
    <constructor-arg>
        <list>
            <!-- SAML Authentication Provider responsible for validating of received SAML messages -->
            <bean id="samlAuthenticationProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider">
                <!-- OPTIONAL property: can be used to store/load user data after login -->
                <!--<property name="userDetails" ref="samlUserDetailsService" />-->
            </bean>
        </list>
    </constructor-arg>
</bean>

<!-- Logger for SAML messages and events -->
<bean id="samlLogger" class="org.springframework.security.saml.log.SAMLDefaultLogger">
    <property name="logMessages" value="true"/>
</bean>

<!-- Central storage of cryptographic keys -->
<bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
    <constructor-arg value="classpath:esia/esia.jks"/>
    <constructor-arg type="java.lang.String" value="******"/>
    <constructor-arg>
        <map>
            <entry key="entryKey" value="******"/>
        </map>
    </constructor-arg>
    <constructor-arg type="java.lang.String" value="someValue"/>
</bean>

<!-- Entry point to initialize authentication, default values taken from properties file -->
<bean id="samlEntryPoint" class="org.springframework.security.saml.SAMLEntryPoint">
    <property name="defaultProfileOptions">
        <bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
            <property name="includeScoping" value="false"/>
            <property name="binding" value="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"/>
        </bean>
    </property>
</bean>

<!-- Filter automatically generates default SP metadata -->
<bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
    <constructor-arg>
        <bean class="org.springframework.security.saml.metadata.MetadataGenerator"/>
    </constructor-arg>
</bean>

<!-- IDP Metadata configuration - paths to metadata of IDPs in circle of trust is here -->
<!-- Do no forget to call iniitalize method on providers -->
<bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
    <constructor-arg>
        <list>
            <bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
                <constructor-arg>
                    <bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
                        <constructor-arg>
                            <value type="java.io.File">classpath:esia/esia_edu_metadata.xml</value>
                        </constructor-arg>
                        <property name="parserPool" ref="parserPool"/>
                    </bean>
                </constructor-arg>
                <constructor-arg>
                    <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                    </bean>
                </constructor-arg>
            </bean>
            <bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
                <constructor-arg>
                    <bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
                        <constructor-arg>
                            <value type="java.io.File">classpath:esia/esia_prod_metadata.xml</value>
                        </constructor-arg>
                        <property name="parserPool" ref="parserPool"/>
                    </bean>
                </constructor-arg>
                <constructor-arg>
                    <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                    </bean>
                </constructor-arg>
            </bean>
            <bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
                <constructor-arg>
                    <bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
                        <constructor-arg>
                            <value type="java.io.File">classpath:esia/shibboleth.xml</value>
                        </constructor-arg>
                        <property name="parserPool" ref="parserPool"/>
                    </bean>
                </constructor-arg>
                <constructor-arg>
                    <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                    </bean>
                </constructor-arg>
            </bean>
        </list>
    </constructor-arg>
    <!-- Set provider edu or prod -->
    <property name="hostedSPName" value="hostname.ru"/>
</bean>

<!-- Provider of default SAML Context -->
<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl"/>

<!-- Processing filter for WebSSO profile messages -->
<bean id="samlWebSSOProcessingFilter" class="org.springframework.security.saml.SAMLProcessingFilter">
    <constructor-arg>
        <value type="java.lang.String">/user/saml/authnrequestresponselistener</value>
    </constructor-arg>
    <property name="authenticationManager" ref="samlAuthenticationManager"/>
    <property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
</bean>

<!-- Class loading incoming SAML messages from httpRequest stream -->
<bean id="processor" class="org.springframework.security.saml.processor.SAMLProcessorImpl">
    <constructor-arg>
        <list>
            <ref bean="redirectBinding"/>
            <ref bean="postBinding"/>
        </list>
    </constructor-arg>
</bean>

<!-- SAML 2.0 WebSSO Assertion Consumer -->
<bean id="webSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerImpl"/>

<!-- SAML 2.0 Holder-of-Key WebSSO Assertion Consumer -->
<bean id="hokWebSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>

<!-- SAML 2.0 Web SSO profile -->
<bean id="webSSOprofile" class="org.springframework.security.saml.websso.WebSSOProfileImpl"/>

<!-- SAML 2.0 Holder-of-Key Web SSO profile -->
<bean id="hokWebSSOProfile" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl"/>

<!-- SAML 2.0 ECP profile -->
<bean id="ecpprofile" class="org.springframework.security.saml.websso.WebSSOProfileECPImpl"/>

<!-- Bindings, encoders and decoders used for creating and parsing messages -->
<bean id="redirectBinding" class="org.springframework.security.saml.processor.HTTPRedirectDeflateBinding">
    <constructor-arg ref="parserPool"/>
</bean>

<bean id="postBinding" class="org.springframework.security.saml.processor.HTTPPostBinding">
    <constructor-arg ref="parserPool"/>
    <constructor-arg ref="velocityEngine"/>
</bean>

<!-- Initialization of OpenSAML library-->
<bean class="org.springframework.security.saml.SAMLBootstrap"/>

<!-- Initialization of the velocity engine -->
<bean id="velocityEngine" class="org.springframework.security.saml.util.VelocityFactory"
      factory-method="getEngine"/>

<!-- XML parser pool needed for OpenSAML parsing -->
<bean id="parserPool" class="org.opensaml.xml.parse.StaticBasicParserPool" init-method="initialize"/>
<bean id="parserPoolHolder" class="org.springframework.security.saml.parser.ParserPoolHolder"/>
  
  

ответ дан 24 июл 2015 в 9:09

Читайте также:  Налог через есиа

Namelles.One's user avatar

relayState – можно не указывать.
Signature в ЕСИА надо указать ‘-‘ примерно так на Ruby:

   params[:SAMLRequest]= Base64.strict_encode64(Zlib::Deflate.deflate(signed_request, 9)[2..-5])
params[:Signature]  = '-'
params[:SigAlg]     = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'
  
  

Подписание дело тонкое: ищите как подписываются xml, куда вставляются блоки, ds:Signature, каноникализация и пр.

Можете посмотреть информацию здесь: http://esia.pro

ответ дан 27 июл 2015 в 10:56

Samoilenko Yuri's user avatar

Исходя из нашего опыта работы могу добавить:

  1. relayState – это уникальный идентификатор сессии в интегрируемом приложении, в результате авторизации ЕСИА вернет его обратно и приложение сможет его связать с запросом

  2. Порядок формировании подписи:

1) выполняется deflate строки запроса – получается byte

2) выполняется подпись полученного на шаге 1 – получается byte

3) выполняется кодирование в base64 полученного на шаге 2

В дополнение могу порекомендовать посмотреть не только готовое решение, упомянутое Samoilenko Yuri
, но и ESIA-Bridge
.

ответ дан 3 фев 2016 в 12:52

Kirill's user avatar

2 бронзовых знака

We would like to use third party cookies and scripts to improve the functionality of this website.
Approve
More info

Аутентификация через госуслуги (ЕСИА)

   https://<ESIA_HOST>/aas/oauth2/ac?client_id={0}&client_secret={1}
&redirect_uri={2}&scope={3}&response_type=code&state={4}
&timestamp={5}&access_type={6}
  
  

Расчет секрета приложения (client_secret)

Секрет приложения расчитывается как подпись конкатенации параметров scope, timestamp, client_id, state
, закодированная как base64 URL safe
.

Пример класса расчета подписи

      

	     

	    
		 
	

	    
		 
	

	      
		      
			
		   
		 

		    
		    

		 // Adding the X509 Certificate
		 
			    

			    
			// Initializing the the BC's Signer
			    
					

			 
					 
							 

			

			    
			

			  
		   
			  
		

		 

	

	  
	  

	      //путь к приватоному ключу ЕСИА
	      //путь к сертификату ЕСИА

	     

		 

		   
		   
		 

			   
			      
				   
				  
				
			
			   
			      
				   
				  
				
			

			    
			   

			   

		    
			 
		
	
  
  

Расчет client_secret

           
  

Если URL сформирован корректно, пользователя перенаправляет на портал ЕСИА, где пользователь проходит аутентификацию, и соглашается на доступ к его данным. Если аутенитфикация прошла успешно, то ЕСИА перенаправляет пользтваеля на целевой сайт, и в URL передает два параметра code
и state

  • state
    – предзназначен для проверки безопасности ответа ЕСИА, должен совпадать со state
    переданным в URL авторизации ЕСИАю
  • code
    – код авторизации, обменивается на access_token, с помощью которого осуществляется доступ к данным.
Читайте также:  Автомобилист в обслуживании автомобилей. Интересные факты и мнения автомобилистов об обслуживании автомобиля

Получение метки доступа (access_token)

После того, как получе код авторизации, его нужно обменять на access_token. Для этого нужно отправить POST запрос по адресу

   https://<ESIA_HOST>/aas/oauth2/te
  
  

Оцените статью