AuthSub в библиотеках клиента протокола передачи данных Google.

Внимание : Эта страница посвящена старым API Google, Google Data API; она актуальна только для API, перечисленных в каталоге Google Data APIs, многие из которых были заменены более новыми API. Информацию о конкретном новом API см. в документации к нему. Информацию об авторизации запросов с использованием более нового API см. в разделе «Аутентификация и авторизация учетных записей Google» .

В этом документе описывается, как использовать клиентские библиотеки Google Data API для подключения к системе аутентификации Google AuthSub для веб-приложений .

Интерфейс AuthSub позволяет веб-приложению получать доступ к сервису Google от имени пользователя. Для обеспечения высокого уровня безопасности интерфейс AuthSub позволяет приложению получать токен аутентификации, не обрабатывая при этом информацию для входа в учетную запись пользователя.

Клиентские библиотеки Google Data API предоставляют методы, которые помогут вам использовать AuthSub в вашем веб-приложении. В частности, существуют методы для формирования URL-адреса запроса, получения одноразового токена аутентификации, обмена одноразового токена на токен сессии и подписи запроса.

Примечание : В клиентской библиотеке JavaScript используется собственная версия AuthSub, называемая AuthSubJS. Информацию об использовании AuthSubJS в ваших JavaScript-приложениях см. в разделе «Использование аутентификации "AuthSub" с клиентской библиотекой JavaScript» .

Аудитория

Этот документ предназначен для программистов, которые хотят, чтобы их веб-приложения получали доступ к сервисам Google от имени пользователей, используя клиентские библиотеки Google Data API.

В этом документе предполагается, что вы знакомы с интерфейсом AuthSub и общим процессом интеграции AuthSub в ваше веб-приложение. Полное описание протокола AuthSub см. в разделе «Аутентификация AuthSub для веб-приложений» .

Использование API AuthSub и Google Data без клиентских библиотек.

Если вы хотите, чтобы ваше веб-приложение взаимодействовало с сервисом Google Data, используя AuthSub в качестве системы аутентификации, то вся необходимая информация содержится в документе «Аутентификация AuthSub для веб-приложений» . Использовать клиентские библиотеки Google Data API вам не обязательно, если вы этого не хотите.

Вот пример того, как ваше приложение может аутентифицировать пользователя с помощью AuthSub:

Ваше приложение формирует соответствующий URL-адрес AuthSub, а затем перенаправляет пользователя на этот URL-адрес для входа в систему; система AuthSub перенаправляет пользователя обратно на указанный вами URL-адрес на вашем сайте и возвращает одноразовый токен; ваше приложение при необходимости обменивает этот токен на токен сессии; затем ваше приложение отправляет токен в заголовке Authorization с каждым запросом, который приложение отправляет в сервис.

Клиентские библиотеки Google Data API упрощают этот процесс авторизации, обрабатывая различные детали за вас. В этом документе объясняется, как это работает.

Работа с AuthSub и API данных Google: примеры клиентской библиотеки

В этом разделе приведен пример использования методов клиентской библиотеки Google Data API в соответствии с шагами, описанными в разделе « Работа с AuthSub » документации AuthSub.

В этом примере мы интегрируем интерфейс AuthSub в веб-приложение, взаимодействующее с Google Календарем (хотя для понимания примера вам не нужно ничего знать о Google Календаре). В примере предполагается, что веб-приложение размещено по адресу example.com .

Определите, какой тип токена использовать ( session=0 или session=1 ).

Вы можете выбрать использование одноразовых токенов ( session=0 ) или сессионных токенов ( session=1 ). В этом документе будут использоваться сессионные токены, поскольку они более полезны в приложениях, которые будут выполнять множество запросов к API. Как обсуждалось в документации AuthSub, если вы решите использовать сессионные токены в своем веб-приложении, вам потребуется самостоятельно управлять хранением токенов. В этом документе управление токенами не рассматривается. Также обратите внимание, что токены, запрошенные с session=0 нельзя впоследствии обменять (обновить) до долгосрочного сессионного токена.

Решите, следует ли регистрировать ваше веб-приложение ( secure=0 или secure=1 ).

AuthSub можно использовать в трех различных режимах: незарегистрированный , зарегистрированный и зарегистрированный с расширенными функциями безопасности . В дальнейшем в этом документе последний вариант будет называться безопасным AuthSub. Хотя незарегистрированный/зарегистрированный режим проще в настройке, чем безопасный AuthSub, Google рекомендует использовать безопасные токены из-за их расширенной защиты.

Как зарегистрироваться

Выбор регистрации для веб-приложений предоставляет вашему приложению следующие преимущества:

  1. Повышенный уровень безопасности.
  2. Заслуживает доверия со стороны Google (на странице авторизации Google пользователю не отображается никаких предупреждений).

Зарегистрировано + Безопасная аутентификация

Если вы выберете защищенный AuthSub, вам потребуется создать пару самоподписываемых закрытого ключа RSA и открытого сертификата в дополнение к регистрации вашего веб-приложения. Примеры создания сертификатов X.509 см. в разделе «Генерация ключей и сертификатов для использования в зарегистрированном режиме» (ниже).

Определите объем доступа к вашим данным.

Для каждого сервиса Google задан параметр scope , который определяет (и, возможно, сужает) доступ токена к данным пользователя. Список доступных значений scope см. в разделе FAQ .

Поскольку мы решили взаимодействовать с API Google Календаря, scope должен быть http://www.google.com/calendar/feeds/ .

Примечание : Всегда устанавливайте значение scope на максимально широкий URL-адрес, если только вам не требуется более тонкое ограничение. Например, более узкая область действия, такая как scope=http://www.google.com/calendar/feeds/default/allcalendars/full , ограничит доступ токена только к ленте allcalendars/full. Использование scope=http://www.google.com/calendar/feeds/ позволит получить доступ ко всем лентам Календаря: http://www.google.com/calendar/feeds/* .

Токены с несколькими областями действия

Чтобы создать токены, обеспечивающие доступ к нескольким API данных Google, разделите каждую область действия пробелом, закодированным в URL-адресе. В приведенном ниже примере создается токен, который будет иметь доступ как к данным контактов пользователя в Google, так и к данным календаря Google.

scope=http://www.google.com/calendar/feeds/%20http://www.google.com/m8/feeds/

Запросите одноразовый токен аутентификации.

Для получения токена AuthSub для конкретного пользователя и конкретной службы ваше приложение должно перенаправить пользователя на URL-адрес AuthSubRequest , который предложит ему войти в свою учетную запись Google. (Более подробную информацию об URL-адресе AuthSubRequest см. в полной версии документа «Аутентификация AuthSub для веб-приложений ».)

Для формирования URL-адреса AuthSubRequest в вашем приложении используйте следующие параметры для каждой клиентской библиотеки:

Java

import com.google.gdata.client.*;

String nextUrl = "http://www.example.com/RetrieveToken.jsp";
String scope = "http://www.google.com/calendar/feeds/";
boolean secure = false;  // set secure=true to request secure AuthSub tokens
boolean session = true;
String authSubUrl = AuthSubUtil.getRequestUrl(nextUrl, scope, secure, session);

Если вы хотите аутентифицировать пользователей в своем домене G Suite:

import com.google.gdata.client.*;

String hostedDomain = "example.com";
String nextUrl = "http://www.example.com/RetrieveToken.jsp";
String scope = "http://www.google.com/calendar/feeds/";
boolean secure = false;  // set secure=true to request AuthSub tokens
boolean session = true;
String authSubUrl = AuthSubUtil.getRequestUrl(hostedDomain, nextUrl, scope, secure, session);

.СЕТЬ

using Google.GData.Client;

String nextUrl = "http://www.example.com/RetrieveToken.aspx";
String scope = "http://www.google.com/calendar/feeds/";
bool secure = false; // set secure=true to request secure AuthSub tokens
bool session = true;
String authSubUrl = AuthSubUtil.getRequestUrl(nextUrl, scope, secure, session);

Если вы хотите аутентифицировать пользователей в своем домене G Suite:

using Google.GData.Client;

String hostedDomain = "example.com";
String nextUrl = "http://www.example.com/RetrieveToken.aspx";
String scope = "http://www.google.com/calendar/feeds/";
bool secure = false; // set secure=true to request secure AuthSub tokens
bool session = true;
String authSubUrl = AuthSubUtil.getRequestUrl(hostedDomain, nextUrl, scope, secure, session);

PHP

require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_AuthSub');

$nextUrl = 'http://www.example.com/RetrieveToken.php';
$scope = 'http://www.google.com/calendar/feeds/';
$secure = 0;  // set $secure=1 to request secure AuthSub tokens
$session = 1;
$authSubUrl = Zend_Gdata_AuthSub::getAuthSubTokenUri($nextUrl, $scope, $secure, $session);

Если вы хотите аутентифицировать пользователей в своем домене G Suite:

require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_AuthSub');

$hostedDomain = 'example.com';
$nextUrl = 'http://www.example.com/RetrieveToken.php';
$scope = 'http://www.google.com/calendar/feeds/';
$secure = 0;  // set $secure=1 to request secure AuthSub tokens
$session = 1;
$authSubUrl = Zend_Gdata_AuthSub::getAuthSubTokenUri($nextUrl, $scope, $secure, $session) . '&hd=' . $hostedDomain;

Python

import gdata.auth

next = 'http://www.example.com/RetrieveToken.pyc'
scope = 'http://www.google.com/calendar/feeds/'
secure = False  # set secure=True to request secure AuthSub tokens
session = True
auth_sub_url = gdata.auth.GenerateAuthSubRequestUrl(next, scope, secure=secure, session=session)

Если вы хотите аутентифицировать пользователей в своем домене G Suite:

import gdata.auth

hosted_domain = 'example.com'
next = 'http://www.example.com/RetrieveToken.pyc'
scope = 'http://www.google.com/calendar/feeds/'
secure = False  # set secure=True to request secure AuthSub tokens
session = True
auth_sub_url = gdata.auth.GenerateAuthSubRequestUrl(next, scope, secure=secure, session=session, domain=hosted_domain)

После формирования URL-адреса "next" ваше приложение может использовать его различными способами для перенаправления пользователя на обработчик AuthSubRequest . Наиболее распространенный подход — отображение страницы, сообщающей пользователю о необходимости перейти по ссылке для авторизации вашего приложения в доступе к его учетной записи Google; затем прикрепление URL-адреса запроса к этой ссылке. Например, в вашем веб-приложении можно вывести следующую строку:

String authorizationUrl =
        "<p>MyApp needs access to your Google Calendar account to read your Calendar feed. " +
        "To authorize MyApp to access your account, <a href=\"" + authSubUrl + "\">log in to your account</a>.</p>";

Пользователь переходит по ссылке на страницу AuthSub в Google и авторизуется. Затем система AuthSub перенаправляет пользователя обратно в ваше приложение, используя предоставленный вами URL-адрес "next".

Извлечь одноразовый токен

Когда Google перенаправляет пользователя обратно в ваше приложение, токен добавляется к следующему URL-адресу в качестве параметра запроса. В приведенных выше примерах после входа пользователя в систему Google перенаправляет на URL-адрес типа http://www.example.com/RetrieveToken?token=DQAADKEDE . Ваше приложение должно извлечь значение токена из параметра запроса URL-адреса.

Если ваше приложение устанавливает аутентификационный cookie в браузере пользователя перед отправкой его в систему AuthSub, то при перенаправлении Google на следующий URL-адрес ваше приложение сможет прочитать аутентификационный cookie, чтобы определить, какой пользователь попал на этот URL. Вы можете использовать такой cookie для сопоставления идентификатора пользователя в вашем приложении с токеном AuthSub, полученным от Google.

Клиентские библиотеки предоставляют удобные методы для извлечения одноразового токена:

Java

String singleUseToken = AuthSubUtil.getTokenFromReply(httpServletRequest.getQueryString());

.СЕТЬ

String singleUseToken = Request.QueryString["token"];
// or
String singleUseToken = AuthSubUtil.getTokenFromReply(new Uri(Request.QueryString));

PHP

$singleUseToken = $_GET['token'];

Python

current_url = 'http://' + req.hostname + req.unparsed_uri
# Unlike the other calls, extract_auth_sub_token_from_url() will create an AuthSubToken or SecureAuthSubToken object.
# Use str(single_use_token) to return the token's string value.
single_use_token = gdata.auth.extract_auth_sub_token_from_url(current_url)

Если вы используете защищенную аутентификацию AuthSub, обязательно настройте свой закрытый ключ RSA таким образом, чтобы создавался SecureAuthSubToken :

f = open('/path/to/yourRSAPrivateKey.pem')
rsa_key = f.read()
f.close()
current_url = 'http://' + req.hostname + req.unparsed_uri
# Unlike the other calls, extract_auth_sub_token_from_url() will create an AuthSubToken or SecureAuthSubToken object.
# Use str(single_use_token) to return the token's string value.
single_use_token = gdata.auth.extract_auth_sub_token_from_url(current_url, rsa_key=rsa_key)

Запросить токен сессии

Токен, полученный по URL-адресу, всегда является одноразовым. Следующий шаг — обновление этого токена до долговременного сессионного токена с помощью URL-адреса AuthSubSessionToken , как описано в полной документации по аутентификации AuthSub для веб-приложений . Если вы используете защищенный AuthSub, вам потребуется установить закрытый ключ RSA перед обменом. Вот несколько примеров использования каждой из клиентских библиотек:

Java

import com.google.gdata.client.*;
import com.google.gdata.client.calendar.*;

String sessionToken = AuthSubUtil.exchangeForSessionToken(singleUseToken, null);

CalendarService calendarService = new CalendarService("google-ExampleApp-v1.0");
calendarService.setAuthSubToken(sessionToken, null);

// ready to interact with Calendar feeds

Для обеспечения безопасности AuthSub передавайте свой закрытый ключ RSA в функцию exchangeForSessionToken вместо значения null :

import com.google.gdata.client.*;
import com.google.gdata.client.calendar.*;

java.security.PrivateKey privateKey =
    AuthSubUtil.getPrivateKeyFromKeystore("AuthSubExample.jks", "privKeyPa$$word", "AuthSubExample", "privKeyPa$$word");
String sessionToken = AuthSubUtil.exchangeForSessionToken(singleUseToken, privateKey);

CalendarService calendarService = new CalendarService("google-ExampleApp-v1.0");
calendarService.setAuthSubToken(sessionToken, privateKey);

// ready to interact with Calendar feeds

.СЕТЬ

using Google.GData.Client;
using Google.GData.Calendar;

String sessionToken = AuthSubUtil.exchangeForSessionToken(singleUseToken, null).ToString();

GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "google-ExampleApp-v1.0");
authFactory.Token = (String) sessionToken;

CalendarService calendarService = new CalendarService(authFactory.ApplicationName);
calendarService.RequestFactory = authFactory;

// ready to interact with Calendar feeds

Для обеспечения безопасности AuthSub передавайте свой закрытый ключ RSA в функцию exchangeForSessionToken вместо значения null :

using Google.GData.Client;
using Google.GData.Calendar;

protected AsymmetricAlgorithm getRsaKey()
{
  X509Certificate2 cert = new X509Certificate2("C:/MyAspSite/test_cert.pfx", "privKeyPa$$word");
  RSACryptoServiceProvider privateKey = cert.PrivateKey as RSACryptoServiceProvider;
  return privateKey;
}

AsymmetricAlgorithm rsaKey = getRsaKey();
String sessionToken = AuthSubUtil.exchangeForSessionToken(singleUseToken, rsaKey).ToString();

GAuthSubRequestFactory authFactory = new GAuthSubRequestFactory("cl", "google-ExampleApp-v1.0");
authFactory.Token = (String) sessionToken;
authFactory.PrivateKey = rsaKey;

CalendarService calendarService = new CalendarService(authFactory.ApplicationName);
calendarService.RequestFactory = authFactory;

// ready to interact with Calendar feeds

PHP

require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_AuthSub');
Zend_Loader::loadClass('Zend_Gdata_Calendar');

$sessionToken = Zend_Gdata_AuthSub::getAuthSubSessionToken($singleUseToken);

// Create a Calendar service object and set the session token for subsequent requests
$calendarService = new Zend_Gdata_Calendar(null, 'google-ExampleApp-v1.0');
$calendarService->setAuthSubToken($sessionToken);

// ready to interact with Calendar feeds

Для безопасной работы AuthSub требуется сначала настроить Zend_Gdata_HttpClient и задать закрытый ключ RSA с помощью setAuthSubPrivateKeyFile() :

require_once 'Zend/Loader.php';
Zend_Loader::loadClass('Zend_Gdata_AuthSub');
Zend_Loader::loadClass('Zend_Gdata_Calendar');

$client = new Zend_Gdata_HttpClient();
$client->setAuthSubPrivateKeyFile('/path/to/myrsakey.pem', null, true);
$sessionToken = Zend_Gdata_AuthSub::getAuthSubSessionToken($singleUseToken, $client);

$calendarService = new Zend_Gdata_Calendar($client, 'google-ExampleApp-v1.0');
$calendarService->setAuthSubToken($sessionToken);

// ready to interact with Calendar feeds

Python

import gdata.calendar
import gdata.calendar.service

calendar_service = gdata.calendar.service.CalendarService()
calendar_service.UpgradeToSessionToken(single_use_token)  # calls gdata.service.SetAuthSubToken() for you

# ready to interact with Calendar feeds

Примечание : Процесс аналогичен для защищенной аутентификации AuthSub, если вы использовали gdata.auth. extract_auth_sub_token_from_url (url, rsa_key=rsa_key) для извлечения одноразового токена.

Примечание : При использовании защищенной аутентификации AuthSub ваш закрытый ключ не передается по сети. Клиентские библиотеки отправляют уникальную подпись, сгенерированную при подписании запроса вашим ключом, а не сам ключ.

Используйте токен сессии

Для аутентификации запросов к серверу можно использовать токен сессии, поместив его в заголовок Authorization, как описано в документации AuthSub.

После установки токена сессии вы можете использовать стандартные вызовы клиентской библиотеки Google Data API для взаимодействия со службой, не задумываясь о токене. Подробную информацию см. в документации клиентской библиотеки и руководстве разработчика Google Data API для используемой вами службы и языка программирования.

Получение информации о токене сессии

Если вы хотите проверить, что ваш клиент и сервер согласны с параметрами токена, вы можете передать токен обработчику AuthSubTokenInfo , который вернет набор пар «имя-значение», содержащих информацию о токене.

Java

Map<String, String> tokenInfo = AuthSubUtil.getTokenInfo(sessionToken, null);

Если вы используете защищенную систему AuthSub, передайте свой закрытый ключ RSA:

Map<String, String> tokenInfo = AuthSubUtil.getTokenInfo(sessionToken, privateKey);

.СЕТЬ

Dictionary<String, String> tokenInfo = AuthSubUtil.GetTokenInfo(sessionToken, null);

Если вы используете защищенную систему AuthSub, передайте свой закрытый ключ RSA:

Dictionary<String, String> tokenInfo = AuthSubUtil.GetTokenInfo(sessionToken, privateKey);

PHP

$tokenInfo = Zend_Gdata_AuthSub::getAuthSubTokenInfo($sessionToken);

Если вы используете защищенную аутентификацию AuthSub, передайте в качестве параметра ваш Zend_Gdata_HttpClient , чтобы запрос был подписан вашим закрытым ключом RSA:

$tokenInfo = Zend_Gdata_AuthSub::getAuthSubTokenInfo($sessionToken, $client);

Python

token_info = calendar_service.AuthSubTokenInfo()

Отозвать токен сессии

Срок действия токенов сессии AuthSub не истекает; ваш клиент может хранить токен сессии столько, сколько необходимо.

Таким образом, когда ваш клиент завершит использование токена сессии, он может отозвать токен с помощью обработчика AuthSubRevokeToken , как описано в документации AuthSub.

Например, если вы хотите управлять токенами традиционным способом, аналогичным работе с сессиями, то ваш клиент может получить токен в начале сессии пользователя и отозвать его в конце сессии.

Для отзыва токена используйте следующие команды в каждой клиентской библиотеке:

Java

AuthSubUtil.revokeToken(sessionToken, null);

Если вы используете защищенную систему AuthSub, передайте свой закрытый ключ RSA:

AuthSubUtil.revokeToken(sessionToken, privateKey);

.СЕТЬ

AuthSubUtil.revokeToken(sessionToken, null);

Если вы используете защищенную систему AuthSub, передайте свой закрытый ключ RSA:

AuthSubUtil.revokeToken(sessionToken, privateKey);

PHP

$wasRevoked = Zend_Gdata_AuthSub::AuthSubRevokeToken($sessionToken);

Если вы используете защищенную аутентификацию AuthSub, передайте в качестве параметра ваш Zend_Gdata_HttpClient , чтобы запрос был подписан вашим закрытым ключом RSA:

$wasRevoked = Zend_Gdata_AuthSub::AuthSubRevokeToken($sessionToken, $client);

Python

calendar_service.RevokeAuthSubToken()

Дополнительные ресурсы и примеры

Вернуться наверх

Генерация самоподписываемого закрытого ключа и открытого сертификата для использования с защищенной системой AuthSub.

Закрытый ключ используется для генерации подписи, которую необходимо прилагать к каждому запросу. Открытый ключ, встроенный в сертификат, используется Google для проверки подписи. Открытый ключ должен представлять собой 1024-битный ключ RSA, закодированный в сертификате X.509 в формате PEM. Сертификат следует отправить в Google во время регистрации.

В следующих разделах приведены примеры генерации ключей и сертификатов с использованием двух конкретных инструментов: утилиты OpenSSL и утилиты keytool из Java.

Эти примеры не относятся исключительно к API данных Google; вы можете использовать те же утилиты для генерации ключей для любых целей.

В примерах предполагается, что ваша компания называется My_Company, находится в городе Маунтин-Вью, штат Калифорния, США, и имеет доменное имя example.com.

Генерация ключей с использованием OpenSSL

Для создания пары ключей RSA и соответствующего сертификата можно использовать следующую команду:

# Generate the RSA keys and certificate
openssl req -x509 -nodes -days 365 -newkey rsa:1024 -sha1 -subj \
  '/C=US/ST=CA/L=Mountain View/CN=www.example.com' -keyout \
  myrsakey.pem -out /tmp/myrsacert.pem

Внимание : Включение параметра -nodes создает закрытый ключ без пароля для защиты. Однако для повышения безопасности рекомендуется опускать этот параметр.

Параметр -sha1 указывает, что ключ будет использоваться для генерации подписей SHA1.

Параметр -subj указывает идентификатор приложения, которое представляет сертификат.

Параметр -keyout указывает файл, в котором будут храниться ключи. Этот файл содержит конфиденциальную информацию и должен быть защищен и не должен передаваться никому.

Параметр -out указывает файл, в котором будет храниться сертификат в формате PEM (который можно отправить в Google при регистрации).

Генерация ключей для .NET-клиента

Платформа .NET не распознает ключи или сертификаты, хранящиеся в формате PEM. Поэтому после создания файла .pem требуется дополнительный шаг:

openssl pkcs12 -export -in test_cert.pem -inkey myrsacert.pem -out myrsacert.pfx -name "Testing Certificate"

На этом этапе генерируется PFX-файл на основе вашего закрытого ключа и сертификата. Этот файл можно импортировать в клиентскую библиотеку .NET для цифровой подписи запросов к API данных Google.

Генерация ключей для Java-клиента

Java-клиент принимает закрытые ключи в формате PKCS#8. После генерации ключа/сертификата, следуя приведенным выше инструкциям , создайте файл .pk8 из сгенерированного файла .pem:

openssl pkcs8 -in myrsakey.pem -topk8 -nocrypt -out myrsakey.pk8

В качестве альтернативы вы можете использовать хранилище ключей Java и утилиту keytool для создания пары ключей RSA и соответствующего сертификата. Используйте следующую команду:

# Generate the RSA keys and certificate
keytool -genkey -v -alias Example -keystore ./Example.jks\
  -keyalg RSA -sigalg SHA1withRSA\
  -dname "CN=www.example.com, OU=Engineering, O=My_Company, L=Mountain  View, ST=CA, C=US"\
  -storepass changeme -keypass changeme

Внимание : " changeme " — плохой пароль; это всего лишь пример.

Параметр -dname указывает идентификатор приложения, которое представляет сертификат. Параметр -storepass указывает пароль для защиты хранилища ключей. Параметр -keypass указывает пароль для защиты закрытого ключа.

Чтобы записать сертификат в файл, который можно использовать в инструменте ManageDomains , воспользуйтесь следующей командой:

# Output the public certificate to a file
keytool -export -rfc -keystore ./Example.jks -storepass changeme \
  -alias Example -file mycert.pem

Вернуться наверх