Внимание : Эта страница посвящена старым 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 рекомендует использовать безопасные токены из-за их расширенной защиты.
Как зарегистрироваться
Выбор регистрации для веб-приложений предоставляет вашему приложению следующие преимущества:
- Повышенный уровень безопасности.
- Заслуживает доверия со стороны 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 anAuthSubTokenorSecureAuthSubTokenobject. # 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 anAuthSubTokenorSecureAuthSubTokenobject. # 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 Data API Tips.
- Пример использования клиентской библиотеки Python AuthSub
- Пример использования клиентской библиотеки Java AuthSub
- Статья: Использование AuthSub с клиентской библиотекой .NET
- Статья: Использование аутентификации "AuthSub" с клиентской библиотекой JavaScript.
Генерация самоподписываемого закрытого ключа и открытого сертификата для использования с защищенной системой 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