Sviluppare funzioni
Prima di distribuire una distribuzione di gateway API, è necessario sviluppare e distribuire le funzioni.
Informazioni sulla business logic
L'ambiente crux dell'implementazione consiste nell'inserire un codice in una funzione. Questo codice potrebbe essere complesso, se necessario, richiamando più endpoint o eseguendo alcune aggregazioni. La funzione di business logic è il codice che verrà richiamato quando richiesto dal gateway API Oracle Cloud Infrastructure.
In questa architettura, il gateway API chiama una funzione Oracle, che attiva l'esecuzione di query su alcuni dati da Oracle Fusion Applications Cloud Service tramite l'API REST, la manipolazione e la restituisce all'utente. Quando si scrive la funzione, è possibile utilizzare qualsiasi framework adatto, ma è necessario conoscere l'impatto di una struttura per le funzioni serverless. In questo esempio sono state utilizzate Java come lingua e libreria Apache HttpClient per la connessione al servizio REST. La libreria Apache è stata scelta poiché è stata facile utilizzare e da implementare; tuttavia, in Java 11 ora è disponibile il nuovo client HTTP che può essere utilizzato.
È inoltre necessario evitare i framework che creano un'istanza di numerosi oggetti in memoria quando si richiamano le API REST, in quanto questi oggetti verranno eliminati in ogni chiamata e pertanto l'esecuzione della funzione viene lenta.
Informazioni sul recupero dei nomi utente e dei ruoli
Quando una funzione viene chiamata dal gateway API Oracle Cloud Infrastructure, il gateway inserisce alcuni metadati nella chiamata utilizzando le intestazioni HTTP. Queste intestazioni sono accessibili mediante Functions SDK.
Ad esempio, nello snippet di codice Java riportato di seguito (estratto dalla classe JWTUtils
nel codice di esempio fornito con questo playbook della soluzione), estrarre il token di autenticazione, convertirlo, quindi restituirlo come parte del corpo del chiamante.
public OutputEvent handleRequest(InputEvent rawInput) {
Optional<string> optionalToken=rawInput.getHeaders().get("Fn-Http-H-Authorization");
if (!optionalToken.isPresent())
{
throw new Exception("No Authentication Bearer token found");
}
String jwtToken=optionalToken.get().substring(TOKEN_BEARER_PREFIX.length());
String[] split_string = jwtToken.split("\\.");
String base64EncodedHeader = split_string[0];
String base64EncodedBody = split_string[1];
String base64EncodedSignature = split_string[2];
byte[] decodedJWT = Base64.getDecoder().decode(base64EncodedBody);
try {
String JSONbody = new String(decodedJWT, "utf-8");
ObjectMapper mapper = new ObjectMapper();
JsonNode root=mapper.readTree(JSONbody);
username=root.get("sub").asText();
System.out.println(“Username = “+username);
} catch (Exception e)
{
Throw new Exception (e.getMessage());
}
Return OutputEvent.fromBytes(
username.getBytes(), // Data
OutputEvent.Status.Success,// Any numeric HTTP status code can be used here
"text/plain");
Il nome utente può essere utilizzato nella funzione per implementare la business logic in base alle esigenze. I ruoli non sono disponibili nel token di autenticazione, ma possono essere sottoposti a query da Oracle Identity Cloud Service utilizzando le API REST.
Quando Oracle API Gateway chiama la funzione, viene inviato anche un numero di intestazioni utili. Queste intestazioni possono essere lette utilizzando l'API della funzione. Le intestazioni utili disponibili in Functions Developer Kit includono:
Fn-Http-Method | Il metodo utilizzato per richiamare la funzione (GET/POST/PUT e così via). |
Fn-Http-Request-Url | L'URL utilizzato per richiamare la funzione, che include i parametri della query. |
Fn-Http-H-User-Agent | I dettagli del client quali il sistema operativo, il fornitore e la versione. |
Ad esempio, utilizzando una combinazione di Fn-Http-Method e Fn-Http-Request-Url, è possibile implementare un router all'interno del codice in modo che la funzione esegua diverse operazioni correlate in base alle modalità di chiamata (ad esempio, PUT, PATCH e così via). Questo approccio viene spesso chiamato pattern “Servizio senza server” e offre il vantaggio che lo sviluppatore deve gestire un numero inferiore di funzioni e ciascuna funzione dispone di un piccolo router che determina la necessità di eseguire.
public OutputEvent handleRequest(InputEvent rawInput, HTTPGatewayContext hctx) throws JsonProcessingException {
String httpMethod = hctx.getMethod();
String httpRequestURI = hctx.getRequestURL();
// etc
}
Informazioni sulla chiamata di Oracle Fusion Applications Cloud Service mediante un token di accesso all'asserzione JWT
È necessario implementare l'asserzione JWT da Oracle Functions utilizzando l'oggetto nell'intestazione Autorizzazione in entrata.
La funzione di esempio fornita con questo playbook di soluzione può eseguire il processo di sicurezza utilizzando una libreria di supporto denominata idcsOAuthAsserter
. La libreria di supporto esegue il flusso completo delle asserzioni OAuth mediante lo scambio di token bearer prima di richiamare Oracle Fusion Applications Cloud Service. Questa libreria è integrata con la funzione di esempio.
La funzione richiede la chiave privata e il certificato pubblico per creare le asserzioni utente e client utilizzate per richiamare Oracle Identity Cloud Service e creare un nuovo token di accesso bearer utilizzando l'asserzione JWT OAuth.
La libreria idcsOAuthAsserter
richiede alcune proprietà che è possibile definire nella configurazione delle funzioni. Tutte le variabili nella tabella seguente sono obbligatorie:
Nome configurazione | Descrizione | Esempio |
---|---|---|
IDCS_URL | URL dell'istanza di Oracle Identity Cloud Service | https://<il nome host del cloud di identità: identity.oraclecloud.com> |
CLIENT_ID | L'ID client dell'applicazione Oracle Identity Cloud Service associato a Oracle Functions e Oracle API Gateway | 1a2b3c4d5e6f7g8h9i01j2k3l4m5o6p7 |
KEY_ID | Alias dei certificati importati nell'applicazione Trusted Oracle Identity Cloud Service | fnassertionkey |
AMBITO | Questo ambito deve corrispondere alla risorsa OAuth di destinazione, ovvero l'applicazione Oracle Identity Cloud Service associata a Oracle Fusion Applications Cloud Service. | urn:opc:resource:fa:instanceid=xxxxxxurn:opc:resource:consumer:: all https://my_fusion_hostname:443/ |
DESTINATARI | Audience per il processo di asserzione. Utilizzare le virgole per separare più valori. | myhostname.identity.oraclecloud.com, https://myfusionservice.dc1.oraclecloud.com |
IDDOMAIN | Nome del tenant dell'istanza Oracle Fusion Applications Cloud Service | mytenant |
La funzione richiede inoltre le proprietà di configurazione per accedere ai segreti per un'asserzione correlata a idcsOAuthAsserter
. L'asserzione JWT richiede un certificato e una chiave privata per generare le asserzioni client e utente. La funzione recupera il keystore con l'OCID specificato in V_KEYSTORE
. L'alias per il recupero di tali informazioni deve corrispondere al valore KEY_ID
nella configurazione. La passphrase sia per il keystore che per la chiave privata deve essere recuperata da Oracle Cloud Infrastructure Vault Secrets Service utilizzando gli OCIDs specificati in V_KS_PASS
e V_PK_PASS
.
Nome configurazione | Descrizione | Esempio |
---|---|---|
V_KEYSTORE | Segreto che contiene il contenuto sicuro memorizzato del keystore | ocid1.vaultsecret.oc1.dc1. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
V_KS_PASS | Segreto che contiene la password sicura memorizzata per il keystore | ocid1.vaultsecret.oc1.dc1. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
V_PK_PASS | Segreto che contiene la password sicura memorizzata per la chiave privata | ocid1.vaultsecret.oc1.dc1. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
Un valore di configurazione supportato aggiuntivo è la proprietà USE_CACHE_TOKEN
, impostata su True
per impostazione predefinita. Questa proprietà consente di memorizzare il token di asserzione Oracle Identity Cloud Service generato per essere riutilizzato in richiami futuri di Oracle Fusion Applications Cloud Service, a condizione che il token rimanga valido. Il token inserito nella cache viene convalidato prima dell'uso confrontando l'oggetto con il token in entrata e verificando l'ora di scadenza per verificare se è ancora valido. In caso contrario, viene richiesto un nuovo token di accesso utilizzando l'asserzione OAuth. Questa funzione può essere disabilitata impostando USE_CACHE_TOKEN
su False
.
La funzione da implementare può utilizzare SecurityHelper object
dalla libreria idcsOAuthAsserter
per estrarre l'oggetto dall'intestazione access-token
, generare un nuovo token di accesso Bearer con l'asserzione JWT OAuth e inviare una richiesta a Oracle Fusion Applications Cloud Service utilizzando il nuovo token di accesso come intestazione Authorization
.
La funzione saasopportunitiesfn
nell'esempio di codice sorgente è già integrata con la libreria idcsOAuthAsserter
. Il seguente snippet di codice è disponibile nel parametro handleRequest
metdhod della funzione di esempio, che mostra come inizializzare gli oggetti di idcsOAuthAsserter
ed eseguire un'eccezione di modifica dei token utilizzando l'asserzione con Oracle Identity Cloud Service:
// Full Oauth scenario Perform exchange of tokens
if(fullOAauth) {
LOGGER.log(Level.INFO, "Full Oauth Assertion scenario - Perform exchange of tokens");
SecurityHelper idcsSecurityHelper = new SecurityHelper(context) // Initialize SecurityHelper with RuntimeContext
.setOciRegion(Region.US_PHOENIX_1) // Specify the OCI region, used to retrieve Secrets.
.extractSubFromJwtTokenHeader(rawInput); // Extracts the subject from Token in Fn-Http-H-Authorization.
// Get OAuth Access token with JWT Assertion using the principal extracted from Fn-Http-H-Access-Token Header
jwttoken = idcsSecurityHelper.getAssertedAccessToken();
LOGGER.log(Level.INFO, "Successfully token retrived with IDCS Assertion");
LOGGER.log(Level.FINEST, "Access Token from assertion [" + jwttoken + "]");
}
Notare in questo snippet che l'oggetto SecurityHelper
è inizializzato con un oggetto di contesto di tipo RuntimeContext
. Verrà utilizzato per inizializzare SecurityHelper
con la configurazione della libreria di supporto idcsOAuthAsserter
.
La funzione saasopportunitiesfn
di esempio è impostata in modo da utilizzare l'area US_PHOENIX_1
, pertanto è necessario modificare l'area nel metodo setOciRegion
mostrato nello snippet in modo che punti all'area.
SecurityHelper
ha anche il metodo extractSubFromJwtTokenHeader
che utilizza l'oggetto InputEvent
del metodo della funzione handleRequest
per estrarre il token Bearer incluso nell'intestazione Authorization
del gateway API. Sarà quindi possibile recuperare un token di accesso in seguito all'asserzione Oracle Identity Cloud Service.
Per ulteriori informazioni sull'uso e l'integrazione di idcsOAuthAsserter
con una funzione, esaminare il file README per idcsOAuthAsserter
nel repository dei codici con il campione di codice scaricabile visualizzato dal libro contabile della soluzione.
Imposta parametri di configurazione
L'ambiente Oracle Functions offre una funzionalità molto utile in cui è possibile definire alcuni parametri all'interno dell'ambiente Oracle Cloud Infrastructure e quindi farvi riferimento dal codice.
In questo caso d'uso, gli URL dei token Fusion e OverrideJWT verranno impostati e un flag denominato full_oauth
, come parametri utilizzati nel codice. Per aggiungere parametri, procedere come segue.
All'interno del codice è possibile accedere a queste variabili di configurazione utilizzando Functions SDK utilizzando un'annotazione Java speciale (@FnConfiguration
) e accedendo ai parametri mediante la variabile di contesto:
private String jwtoverride = "";
private String fusionHostname = "";
private String fnURIBase ="/fnsaaspoc/opportunities";
/**
* @param ctx : Runtime context passed in by Fn
*/
@FnConfiguration
public void config(RuntimeContext ctx) {
fusionHostname = ctx.getConfigurationByKey("fusionhost").orElse("NOTSET");
jwtoverride = ctx.getConfigurationByKey("overridejwt").orElse("NOTSET");
fullOAauth = Boolean.parseBoolean(ctx.getConfigurationByKey("full_oauth").orElse("false"));
LOGGER.info("Configuration read : jwt=" + jwtoverride + " saasurl=" + fusionHostname);
}
Inoltre, poiché questa soluzione utilizza la libreria di supporto idcsOAuthAsserter
, è necessario fornire nella Configurazione funzioni le variabili specifiche descritte nella sezione precedente per utilizzare l'asserzione OAuth Oracle Identity Cloud Service per lo scambio dei token di accesso. Poiché questo processo richiede diverse configurazioni obbligatorie, si consiglia di impostare la configurazione della funzione utilizzando l'approccio file yaml. Ad esempio:
config:
AUDIENCE: <AUDIENCE_VALUES>
CLIENT_ID: <YOUR_CLIENT_ID>
IDCS_URL: <YOUR_IDCS_URL>
IDDOMAIN: <YOUR_FA_TENANT_NAME>
KEY_ID: <YOUR_IDCS_URL>
SCOPE: <FA_RESOURCE_SCOPE>
V_KEYSTORE: <YOUR_KS_OCID>
V_KS_PASS: <YOUR_KSPASS_OCID>
V_PK_PASS: <YOUR_PKPASS_OCID>
fusionhost: <value>
overridejwt: <value>
full_oauth: <value>
Passare il token di autenticazione utente a Fusion Applications
La funzione deve gestire il token di autenticazione utente per le interazioni API REST sicure.
Se si richiama la funzione, verrà inviata anche una variabile di intestazione “autorizzazione” che conterrà un token di autenticazione. Questo token viene generato dal server delle identità dell'applicazione chiamante che è lo stesso server delle identità utilizzato dalla funzione gateway API Oracle Cloud Infrastructure per convalidare la richiesta.
L'approccio descritto in questa riproduzione di soluzioni consente di utilizzare l'asserzione JWT OAuth Oracle Identity Cloud Service per eseguire lo scambio di token mediante la libreria di supporto idcsOAuthAsserter
. Fornisce un ulteriore layer di sicurezza per il richiamo da Oracle Functions a Oracle Fusion Applications Cloud Service. Come mostrato nel diagramma dell'architettura, la funzione con query di asserzione JWT OAuth per il token incluso nella chiamata in entrata dall'intestazione del gateway API e la utilizza per essere modificata da un altro token durante il processo di asserzione con Oracle Identity Cloud Service. Questo nuovo token verrà utilizzato nella chiamata in uscita al server di destinazione ( Oracle Fusion Applications Cloud Service ) e verrà eseguito ( Oracle Fusion Applications Cloud Service ) come utente in Oracle Visual Builder.
Nella funzione di esempio fornita (saasopportunitiesfn
) è presente una configurazione denominata full_oauth
che, per impostazione predefinita, è impostata su True
e il funzionamento è descritto in precedenza.
Facoltativamente, è possibile impostare full_oauth
su False
. In questo caso, la funzione esegue una query sul token che viene inserito nella chiamata in entrata dall'intestazione del gateway API e lo utilizza nella chiamata in uscita a Oracle Fusion Applications Cloud Service. Nessun secondo token generato.
Lo snippet di codice seguente utilizza la libreria HTTP Apache e richiama l'API REST Oracle Fusion Applications Cloud Service utilizzando il token di autenticazione passato.
String fusionURL=”<yourfusionresturl>”;
HttpClient client = HttpClients.custom().build();
HttpUriRequest request = RequestBuilder.get().setUri(fusionURL).
setHeader(HttpHeaders.CONTENT_TYPE, "application/json").
setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + jwtToken).
build();
HttpResponse response = client.execute(request);
responseJson = EntityUtils.toString(response.getEntity());
status = response.getStatusLine().getStatusCode();
Compila e distribuisci la funzione
In Oracle Functions creare un'applicazione per la funzione, quindi distribuire la funzione.
Definisci facoltativamente una funzione di autenticazione in Oracle Cloud Infrastructure
Il gateway API Oracle Cloud Infrastructure supporta IDCS come provider di autenticazione. Tuttavia, il gateway consente anche la definizione di una funzione che può richiamare. Facoltativamente, è possibile creare una funzione di autenticazione custom utilizzando questa funzione.
La funzione di autenticazione personalizzata riceve una chiamata dal gateway, facendola precedere l'intestazione di autorizzazione in entrata. Se la funzione restituisce true, la chiamata di funzione è consentita. Se invece restituisce false, la richiesta viene rifiutata con un codice di errore HTTP 401. La funzione viene fornita nel formato del codice sorgente e viene distribuita all'interno delle funzioni, a cui viene quindi fatto riferimento nel file di distribuzione GATEWAY dell'API OCI mediante il relativo OCID. È possibile trovare l'OCID passando alla funzione distribuita nella console ed espandendone la colonna OCID. Prima di poter distribuire la funzione, è necessario modificare il file ResourceServerConfig.java
, che definisce la modalità di connessione della funzione a Oracle Identity Cloud Service e l'applicazione Oracle Identity Cloud Service OAuth utilizzata.
L'esempio di funzione riportato di seguito evita valori riservati alla codifica complessa, ad esempio il segreto client. Nelle quattro righe sotto il commento // KMS Key for IDCS Client Secret
, il codice decifra il segreto OAuth utilizzando la funzione di gestione delle chiavi di Oracle Cloud Infrastructure, Oracle Cloud Infrastructure Vault. Immettere questi valori nella console di Oracle Cloud Infrastructure prima di distribuire la funzione.