AuthSub nelle librerie client del protocollo Google Data

Avviso: questa pagina riguarda le API precedenti di Google, le API Google Data; è pertinente solo alle API elencate nella directory delle API Google Data, molte delle quali sono state sostituite da API più recenti. Per informazioni su una nuova API specifica, consulta la documentazione della nuova API. Per informazioni sull'autorizzazione delle richieste con un'API più recente, vedi Autenticazione e autorizzazione dell'Account Google.

Questo documento descrive come utilizzare le librerie client Google Data API per connettersi all'autenticazione AuthSub per applicazioni web di Google.

L'interfaccia AuthSub consente a un'applicazione basata sul web di accedere a un servizio Google per conto di un utente. Per mantenere un elevato livello di sicurezza, l'interfaccia AuthSub consente all'applicazione di ottenere un token di autenticazione senza mai gestire le credenziali di accesso all'account dell'utente.

Le librerie client dell'API Google Data forniscono metodi per aiutarti a utilizzare AuthSub nella tua applicazione web. Nello specifico, esistono metodi per creare l'URL della richiesta, acquisire un token di autenticazione monouso, scambiare il token monouso con un token di sessione e firmare la richiesta.

Nota: la libreria client JavaScript ha una propria versione di AuthSub, chiamata AuthSubJS. Per informazioni su come utilizzare AuthSubJS nelle applicazioni JavaScript, consulta Utilizzo dell'autenticazione "AuthSub" con la libreria client JavaScript.

Pubblico

Questo documento è destinato ai programmatori che vogliono che le loro applicazioni basate sul web accedano ai servizi Google per conto degli utenti, utilizzando le librerie client delle API di Google Data.

Questo documento presuppone che tu abbia familiarità con l'interfaccia AuthSub e con la procedura generale per incorporare AuthSub nella tua applicazione web. Per una descrizione completa del protocollo AuthSub, consulta Autenticazione AuthSub per applicazioni web.

Utilizzo di AuthSub e delle API di Google Data senza le librerie client

Se vuoi che il client dell'applicazione web interagisca con un servizio Google Data utilizzando AuthSub come sistema di autenticazione, tutto ciò che devi sapere è descritto in Autenticazione AuthSub per applicazioni web. Non è necessario utilizzare le librerie client delle API di dati di Google se non vuoi.

Ecco una panoramica di come la tua applicazione potrebbe autenticare un utente utilizzando AuthSub:

La tua applicazione crea l'URL AuthSub appropriato e poi invia l'utente a questo URL in modo che possa accedere. Il sistema AuthSub reindirizza l'utente all'URL del tuo sito che hai specificato e restituisce un token monouso. La tua applicazione scambia facoltativamente questo token con un token di sessione, quindi lo invia nell'intestazione Authorization con ogni richiesta che invia al servizio.

Le librerie client delle API di dati di Google semplificano questo processo di autorizzazione gestendo vari dettagli per te. Questo documento spiega come.

Utilizzo di AuthSub e delle API Google Data: esempi di librerie client

Questa sezione mostra un esempio di utilizzo dei metodi della libreria client delle API di Google Data per seguire i passaggi descritti nella sezione "Utilizzo di AuthSub" della documentazione di AuthSub.

In questo esempio, integriamo l'interfaccia AuthSub in un'applicazione web che interagisce con Google Calendar (anche se non è necessario sapere nulla di Google Calendar per seguire l'esempio). L'esempio presuppone che l'applicazione web sia ospitata all'indirizzo example.com.

Decidi quale tipo di token utilizzare (session=0 o session=1)

Puoi scegliere di utilizzare token monouso (session=0) o token di sessione (session=1). Questo documento utilizzerà i token di sessione, in quanto sono più utili nelle applicazioni che effettuano più richieste API. Come descritto nella documentazione di AuthSub, se decidi di utilizzare i token di sessione nella tua applicazione web, dovrai gestire autonomamente l'archiviazione dei token. Questo documento non tratta la gestione dei token. Tieni inoltre presente che i token richiesti con session=0 non possono essere scambiati (eseguiti l'upgrade) in un secondo momento con un token di sessione di lunga durata.

Decidi se registrare la tua applicazione web (secure=0 o secure=1)

AuthSub può essere utilizzato in tre diverse modalità: non registrata, registrata e registrata con sicurezza avanzata. Il resto di questo documento farà riferimento all'ultima opzione come AuthSub sicuro. Sebbene la modalità non registrata/registrata sia più semplice da configurare rispetto ad AuthSub sicuro, Google ti consiglia di utilizzare token sicuri per una maggiore sicurezza.

Come registrarsi

Se scegli Registrazione per applicazioni basate sul web, la tua applicazione avrà i seguenti vantaggi:

  1. Un livello di sicurezza più elevato.
  2. Essere considerato attendibile da Google (nessun avviso viene mostrato all'utente nella pagina di autorizzazione di Google).

Registrato + AuthSub sicuro

Se scegli AuthSub sicuro, devi creare una coppia di certificati pubblici e chiavi private RSA autofirmati, oltre a registrare la tua applicazione web. Per esempi di creazione di certificati X.509, vedi Generare chiavi e certificati da utilizzare con la modalità registrata (di seguito).

Determinare l'ambito dell'accesso ai dati

Ogni servizio Google definisce un valore scope che determina (e possibilmente limita) l'accesso di un token ai dati dell'utente. Consulta le domande frequenti per l'elenco dei valori scope disponibili.

Poiché abbiamo deciso di interagire con l'API Google Calendar, scope deve essere http://www.google.com/calendar/feeds/.

Nota: imposta sempre il valore dell'ambito sull'URL più ampio possibile, a meno che tu non abbia bisogno di una limitazione più precisa. Ad esempio, un ambito più ristretto come scope=http://www.google.com/calendar/feeds/default/allcalendars/full limiterà l'accesso del token solo al feed allcalendars/full. L'utilizzo di scope=http://www.google.com/calendar/feeds/ consentirà l'accesso a tutti i feed di Calendar: http://www.google.com/calendar/feeds/*.

Token con più ambiti

Per creare token che accedono a più API di dati di Google, separa ogni ambito con uno spazio codificato in URL. L'esempio seguente crea un token che avrà accesso sia ai dati di Google Contatti che a quelli di Google Calendar di un utente.

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

Richiedere un token di autenticazione monouso

Per acquisire un token AuthSub per un determinato utente e un determinato servizio, l'applicazione deve reindirizzare l'utente all'URL AuthSubRequest, che gli chiede di accedere al proprio Account Google. Per saperne di più sull'URL AuthSubRequest, consulta la documentazione completa sull'autenticazione AuthSub per applicazioni web.

Per creare l'URL AuthSubRequest nella tua applicazione, utilizza quanto segue per ogni libreria client:

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);

Se vuoi autenticare gli utenti sul tuo dominio 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);

.NET

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);

Se vuoi autenticare gli utenti sul tuo dominio 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);

Se vuoi autenticare gli utenti sul tuo dominio 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)

Se vuoi autenticare gli utenti sul tuo dominio 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)

Dopo aver creato l'URL "next", la tua applicazione può utilizzarlo in vari modi per inviare l'utente al gestore AuthSubRequest. L'approccio più comune è visualizzare una pagina che comunica all'utente che deve seguire un link per autorizzare l'applicazione ad accedere al proprio Account Google, quindi allegare l'URL della richiesta al link. Ad esempio, potresti generare la seguente stringa nella tua app web:

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>";

L'utente segue il link alla pagina AuthSub di Google ed esegue l'accesso. Il sistema AuthSub reindirizza quindi l'utente alla tua applicazione utilizzando l'URL "next" che hai fornito.

Estrai il token monouso

Quando Google reindirizza alla tua applicazione, il token viene aggiunto all'URL "next" come parametro di ricerca. Nel caso degli esempi precedenti, dopo l'accesso dell'utente, Google reindirizza a un URL come http://www.example.com/RetrieveToken?token=DQAADKEDE. L'applicazione deve estrarre il valore del token dal parametro di query dell'URL.

Se la tua applicazione ha impostato un cookie di autenticazione nel browser dell'utente prima di inviarlo al sistema AuthSub, quando Google reindirizza all'URL "next", la tua applicazione può leggere il cookie di autenticazione per riconoscere l'utente che è arrivato a quell'URL. Puoi utilizzare questo cookie per associare un ID utente nella tua applicazione al token AuthSub recuperato da Google.

Le librerie client forniscono metodi pratici per estrarre il token monouso:

Java

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

.NET

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)

Se utilizzi AuthSub sicuro, assicurati di impostare la chiave privata RSA in modo che venga creato un 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)

Richiedere un token di sessione

Il token recuperato dall'URL è sempre un token monouso. Il passaggio successivo consiste nell'eseguire l'upgrade di questo token per un token di sessione di lunga durata utilizzando l'URL AuthSubSessionToken, come descritto nella documentazione completa relativa all'autenticazione AuthSub per le applicazioni web. Se utilizzi AuthSub sicuro, devi impostare la chiave privata RSA prima di effettuare lo scambio. Ecco alcuni esempi che utilizzano ciascuna delle librerie client:

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

Per AuthSub sicuro, passa la chiave privata RSA a exchangeForSessionToken anziché a 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

.NET

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

Per AuthSub sicuro, passa la chiave privata RSA a exchangeForSessionToken anziché a 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

Per AuthSub sicuro, lo scambio richiede di configurare prima un Zend_Gdata_HttpClient e impostare la chiave privata RSA utilizzando 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

Nota: la procedura è la stessa per AuthSub sicuro, a condizione che tu abbia utilizzato gdata.auth.extract_auth_sub_token_from_url(url, rsa_key=rsa_key) per estrarre il token monouso.

Nota: quando utilizzi AuthSub sicuro, la tua chiave privata non viene inviata tramite la rete. Le librerie client inviano la firma univoca generata firmando la richiesta con la tua chiave, non la chiave stessa.

Utilizzare il token di sessione

Puoi utilizzare il token di sessione per autenticare le richieste al server inserendolo nell'intestazione Authorization, come descritto nella documentazione di AuthSub.

Dopo aver impostato il token di sessione, puoi utilizzare le chiamate standard della libreria client delle API di dati di Google per interagire con il servizio, senza dover pensare al token. Per maggiori dettagli, consulta la documentazione della libreria client e la guida per gli sviluppatori delle API di dati di Google per il servizio e la lingua con cui interagisci.

Recupero delle informazioni su un token di sessione

Se vuoi verificare che il client e il server concordino sui parametri del token, puoi passarlo al gestore AuthSubTokenInfo, che restituisce un insieme di coppie nome-valore contenenti informazioni sul token.

Java

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

Se utilizzi AuthSub sicuro, inserisci la chiave privata RSA:

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

.NET

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

Se utilizzi AuthSub sicuro, inserisci la chiave privata RSA:

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

PHP

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

Se utilizzi AuthSub sicuro, trasmetti il tuo Zend_Gdata_HttpClient in modo che la richiesta venga firmata con la tua chiave privata RSA:

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

Python

token_info = calendar_service.AuthSubTokenInfo()

Revocare un token di sessione

I token di sessione AuthSub non scadono; il client può archiviarli per tutto il tempo necessario.

Pertanto, quando il client ha terminato di utilizzare il token di sessione, può revocarlo utilizzando il gestore AuthSubRevokeToken, come descritto nella documentazione di AuthSub.

Ad esempio, se vuoi gestire i token in modo simile a una sessione tradizionale, il tuo client può ottenere un token all'inizio della sessione di un utente e revocarlo al termine della sessione.

Per revocare un token, utilizza quanto segue in ogni libreria client:

Java

AuthSubUtil.revokeToken(sessionToken, null);

Se utilizzi AuthSub sicuro, inserisci la chiave privata RSA:

AuthSubUtil.revokeToken(sessionToken, privateKey);

.NET

AuthSubUtil.revokeToken(sessionToken, null);

Se utilizzi AuthSub sicuro, inserisci la chiave privata RSA:

AuthSubUtil.revokeToken(sessionToken, privateKey);

PHP

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

Se utilizzi AuthSub sicuro, trasmetti il tuo Zend_Gdata_HttpClient in modo che la richiesta venga firmata con la tua chiave privata RSA:

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

Python

calendar_service.RevokeAuthSubToken()

Risorse aggiuntive ed esempi

Torna all'inizio

Generazione di una chiave privata autofirmata e di un certificato pubblico da utilizzare con AuthSub sicuro

La chiave privata viene utilizzata per generare una firma, che deve essere inclusa in ogni richiesta. La chiave pubblica incorporata nel certificato viene utilizzata da Google per verificare la firma. La chiave pubblica deve essere una chiave RSA a 1024 bit codificata in un certificato X.509 in formato PEM. Il certificato deve essere inviato a Google al momento della registrazione.

Le sezioni seguenti forniscono esempi di come generare chiavi e certificati utilizzando due strumenti particolari: l'utilità OpenSSL e l'utilità keytool di Java.

Questi esempi non sono specifici delle API Google Data; puoi utilizzare le stesse utilità per generare chiavi per qualsiasi scopo.

Gli esempi presuppongono che la tua azienda si chiami My_Company e si trovi a Mountain View, in California, Stati Uniti, con il nome di dominio example.com.

Generazione di chiavi utilizzando OpenSSL

Per creare una coppia di chiavi RSA e il certificato corrispondente, puoi utilizzare il seguente comando:

# 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

Avviso: l'inclusione del parametro -nodes crea una chiave privata senza password per proteggerla. Tuttavia, ti consigliamo di omettere questo parametro per una maggiore sicurezza.

Il parametro -sha1 specifica che la chiave verrà utilizzata per generare firme SHA1.

Il parametro -subj specifica l'identità dell'applicazione rappresentata dal certificato.

Il parametro -keyout specifica il file che conterrà le chiavi. Questo file contiene informazioni sensibili e deve essere protetto e non condiviso con nessuno.

Il parametro -out specifica il file che conterrà il certificato in formato PEM (che può essere inviato a Google durante la registrazione).

Generare chiavi per il client .NET

Il framework .NET non riconosce le chiavi o i certificati archiviati in formato PEM. Pertanto, una volta creato il file .pem, è necessario un passaggio aggiuntivo:

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

Questo passaggio genera un file PFX dalla chiave privata e dal certificato. Questo file può essere importato nella libreria client .NET per firmare digitalmente le richieste effettuate alle API di Google Data.

Generazione di chiavi per il client Java

Il client Java accetta le chiavi private nel formato PKCS#8. Dopo aver generato una chiave/un certificato utilizzando le istruzioni riportate sopra, crea un file .pk8 dal file .pem generato:

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

In alternativa, puoi utilizzare il keystore Java e l'utilità keytool per creare una coppia di chiavi RSA e il certificato corrispondente. Utilizza il seguente comando:

# 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

Avviso: "changeme" non è una password sicura, è solo un esempio.

Il parametro -dname specifica l'identità dell'applicazione rappresentata dal certificato. Il parametro -storepass specifica la password per proteggere il keystore. Il parametro -keypass specifica la password per proteggere la chiave privata.

Per scrivere il certificato in un file che può essere utilizzato nello strumento ManageDomains, utilizza questo comando:

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

Torna all'inizio