Funciones de desarrollo
Antes de desplegar un despliegue de gateway de API, necesitará desarrollar y desplegar las funciones.
Acerca de la Lógica de Negocio
La crux de la implantación es colocar algún código en una función. Este código podría ser lo más complejo que sea necesario, llamando a varios puntos finales o realizar alguna agregación. La función de lógica de negocio es el código que se llamará cuando la necesite el gateway de API de Oracle Cloud Infrastructure.
En esta arquitectura de ejemplo, el gateway de API llama a una función de Oracle que, a su vez, consulta algunos datos de Oracle Fusion Applications Cloud Service mediante la API de REST, los manipula y los devuelve al usuario. Al escribir la función en sí, puede utilizar cualquier marco adecuado que desee, pero debe tener en cuenta el impacto de un marco en funciones sin servidor. En este ejemplo, hemos utilizado Java como idioma y la biblioteca Apache HttpClient para conectarse a REST Service. Se ha seleccionado la biblioteca Apache porque es fácil de usar y fácil de implementar; sin embargo, en Java 11, ahora tendremos el nuevo cliente HTTP que también podría utilizarse.
También debe evitar marcos que instancian muchos objetos en memoria al llamar a las API REST, ya que estos objetos se desecharán en cada llamada y, por lo tanto, ralentizarán la ejecución de la función.
Acerca de la obtención de nombres de usuario y funciones
Cuando un gateway de API de Oracle Cloud Infrastructure llama a una función, el gateway inserta algunos metadatos en la llamada mediante cabeceras HTTP. A estas cabeceras se puede acceder mediante el SDK de funciones.
Por ejemplo, en el siguiente fragmento de código Java (que se extrae de la clase JWTUtils
en el código de ejemplo proporcionado con esta solución playbook), se extrae el token de autenticación, se descodifica y, a continuación, se devuelve como parte del cuerpo al emisor de llamada.
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");
El nombre de usuario se puede utilizar en la función para implantar la lógica de negocio según sea necesario. Los roles no están disponibles en el token de autenticación, pero se pueden consultar desde Oracle Identity Cloud Service mediante las API de REST.
Cuando Oracle API Gateway llama a la función, también se envían una serie de cabeceras útiles. Estas cabeceras se pueden leer mediante la API de la función. Las cabeceras útiles disponibles en el Developer Kit de funciones incluyen:
Fn-Http-Method | Método utilizado para llamar a la función (GET/POST/PUT etc.). |
Fn-Http-Request-Url | URL utilizada para llamar a la función; incluye los parámetros de consulta. |
Fn-Http-H-User-Agent | Detalles del cliente, como el sistema operativo, el proveedor y la versión. |
Por ejemplo, utilizando una combinación de Fn-Http-Method y Fn-Http-Request-Url puede implementar un enrutador en su código para que su función realice diferentes cosas relacionadas según cómo se haya llamado (como PUT, PATCH, etc.). Este enfoque se denomina a menudo el patrón “Servicio sin Servidor” y tiene la ventaja de que el desarrollador tiene para mantener menos funciones, y cada función tiene un pequeño enrutador que determina lo que necesita hacer.
public OutputEvent handleRequest(InputEvent rawInput, HTTPGatewayContext hctx) throws JsonProcessingException {
String httpMethod = hctx.getMethod();
String httpRequestURI = hctx.getRequestURL();
// etc
}
Acerca de la Llamada a Oracle Fusion Applications Cloud Service mediante un Token de Acceso de Afirmación de JWT
Debe implantar la afirmación de JWT desde Oracle Functions mediante el asunto en la cabecera de autorización entrante.
La función de muestra proporcionada con este libro de reproducción de soluciones puede realizar este proceso de seguridad mediante una biblioteca externa denominada idcsOAuthAsserter
. La biblioteca externa realiza el flujo completo de afirmación de OAuth mediante un intercambio de tokens de portador antes de llamar a Oracle Fusion Applications Cloud Service. Esta biblioteca está integrada con la función de ejemplo.
La función necesita la clave privada y el certificado público para crear las afirmaciones de usuario y cliente utilizadas para llamar a Oracle Identity Cloud Service para crear un nuevo token de acceso de portador mediante la afirmación de JWT de OAuth.
La biblioteca idcsOAuthAsserter
requiere algunas propiedades que puede definir en la configuración de funciones. Todas las variables de la siguiente tabla son obligatorias:
Nombre de Configuración | Descripción | Ejemplo |
---|---|---|
IDCS_URL | URL de instancia de Oracle Identity Cloud Service | https://<su nube de identidad hostname.identity.oraclecloud.com> |
CLIENT_ID | Su identificador de cliente de aplicación de Oracle Identity Cloud Service asociado a Oracle Functions y Oracle API Gateway | 1a2b3c4d5e6f7g8h9i01j2k3l4m5o6p7 |
KEY_ID | Alias de los certificados importados a la aplicación Oracle Identity Cloud Service de confianza | fnassertionkey |
ÁMBITO | Este ámbito debe coincidir con el recurso OAuth de destino, que es la aplicación Oracle Identity Cloud Service asociada a Oracle Fusion Applications Cloud Service | urn:opc:resource:fa:instanceid=xxxxxxxxxurn:opc:resource:consumer:: all https://my_fusion_hostname:443/ |
DESTINATARIOS | Públicos del proceso de afirmación. Separe los diversos valores con comas. | myhostname.identity.oraclecloud.com, https://myfusionservice.dc1.oraclecloud.com |
IDDOMAIN | Nombre del inquilino de la instancia de Oracle Fusion Applications Cloud Service | mytenant |
La función también necesitará propiedades de configuración para acceder a secretos para la afirmación relacionada con idcsOAuthAsserter
. La afirmación de JWT necesita un certificado y una clave privada para generar las afirmaciones de cliente y usuario. La función recupera el almacén de claves con el OCID especificado en V_KEYSTORE
. El alias para recuperar dicha información debe coincidir con el valor KEY_ID
de la configuración. La contraseña para el almacén de claves y la clave privada se debe recuperar del servicio Secretos de Oracle Cloud Infrastructure Vault mediante el OCID especificado en V_KS_PASS
y V_PK_PASS
.
Nombre de Configuración | Descripción | Ejemplo |
---|---|---|
V_KEYSTORE | Secreto que contiene el contenido almacenado seguro del almacén de claves | ocid1.vaultsecret.oc1.dc1. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
V_KS_PASS | Secreto que contiene la contraseña almacenada segura para el almacén de claves | ocid1.vaultsecret.oc1.dc1. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
V_PK_PASS | Secreto que contiene la contraseña almacenada segura para la clave privada | ocid1.vaultsecret.oc1.dc1. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
Un valor de configuración adicional soportado es la propiedad USE_CACHE_TOKEN
, que se define por defecto en True
. Esta propiedad permite almacenar el token de afirmación de Oracle Identity Cloud Service generado que se va a volver a utilizar en llamadas futuras de Oracle Fusion Applications Cloud Service, mientras el token siga siendo válido. El token almacenado en caché se valida antes de utilizarlo comparando el asunto con el token entrante y verificando la hora de vencimiento para comprobar si todavía es válido. Si no es así, se solicita un nuevo token de acceso mediante la afirmación de OAuth. Esta función se puede desactivar definiendo USE_CACHE_TOKEN
en False
.
La función que se va a implantar puede utilizar SecurityHelper object
de la biblioteca idcsOAuthAsserter
para extraer el asunto de la cabecera access-token
, generar un nuevo token de acceso de portador con la afirmación de JWT de OAuth y enviar una solicitud a Oracle Fusion Applications Cloud Service mediante el nuevo token de acceso como cabecera Authorization
.
La función saasopportunitiesfn
en el ejemplo de código fuente ya está integrada con la biblioteca idcsOAuthAsserter
. El siguiente fragmento de código está disponible en la metdhod handleRequest
de la función de ejemplo, que muestra cómo inicializar los objetos de idcsOAuthAsserter
y realizar un cambio de tokens mediante la afirmación 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 + "]");
}
Observe en este fragmento que el objeto SecurityHelper
se inicializa con un objeto de contexto de tipo RuntimeContext
. Se utilizará para inicializar SecurityHelper
con la configuración de la biblioteca externa idcsOAuthAsserter
.
La función saasopportunitiesfn
de ejemplo está definida para utilizar la región US_PHOENIX_1
, por lo que debe cambiar la región en el método setOciRegion
mostrado en el fragmento para apuntar a la región.
SecurityHelper
también tiene el método extractSubFromJwtTokenHeader
que toma el objeto InputEvent
del método de función handleRequest
para extraer el token de portador que viene en la cabecera Authorization
del gateway de API. A continuación, debería poder recuperar un token de acceso como resultado de la afirmación de Oracle Identity Cloud Service.
Para obtener más información sobre el uso de idcsOAuthAsserter
y la integración con una función, consulte el archivo README para idcsOAuthAsserter
en el repositorio de códigos con el ejemplo de código para descargar adjunto a este libro de reproducción de soluciones.
Definir Parámetros de Configuración
El entorno de Oracle Functions proporciona una funcionalidad muy útil donde puede definir algunos parámetros en el entorno de Oracle Cloud Infrastructure y, a continuación, hacer referencia a ellos desde su código.
En este caso de uso, definirá las URL de token de Fusion y OverrideJWT, y un indicador denominado full_oauth
, como parámetros que se utilizan en el código. Para agregar parámetros:
Dentro del código, puede acceder a estas variables de configuración mediante el SDK de funciones utilizando una anotación especial de Java (@FnConfiguration
) y accediendo a los parámetros mediante la variable de contexto:
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);
}
Además, puesto que esta solución utiliza la biblioteca externa idcsOAuthAsserter
, debe proporcionar en Configuración de función las variables específicas descritas en la sección anterior para usar la afirmación de Oracle Identity Cloud Service OAuth para intercambiar tokens de acceso. Puesto que este proceso requiere varias configuraciones obligatorias, le recomendamos que defina la configuración de función mediante el enfoque de archivo yaml. Por ejemplo:
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>
Transferir Token de Autenticación de Usuario a Fusion Applications
La función necesita manejar el token de autenticación de usuario para interacciones seguras de la API REST.
Cuando se llama a la función, también se le ha enviado una variable de cabecera “autorización” que contendrá un token de autenticación. Este token se genera mediante el servidor de identidad de la aplicación que realiza la llamada, que es el mismo servidor de identidad que la función de gateway de la API de Oracle Cloud Infrastructure que utiliza para validar la solicitud.
El enfoque que se describe en esta solución es el encargado de utilizar la afirmación de JWT de OAuth de Oracle Identity Cloud Service para realizar el intercambio de tokens mediante la biblioteca Helper idcsOAuthAsserter
. Proporciona una capa de seguridad adicional para la llamada de Oracle Functions a Oracle Fusion Applications Cloud Service. Como se muestra en el diagrama de arquitectura, la función con consultas de afirmación de JWT de OAuth para el token que llega a la llamada entrante desde la cabecera del gateway de API y la utiliza para ser cambiados para otro token durante el proceso de afirmación con Oracle Identity Cloud Service. Este nuevo token se utilizará en la llamada saliente al servidor de destino ( Oracle Fusion Applications Cloud Service ) y ( Oracle Fusion Applications Cloud Service ) ejecutará la llamada como usuario en Oracle Visual Builder.
En la función de ejemplo proporcionada (saasopportunitiesfn
), hay una configuración denominada full_oauth
, que, por defecto, está definida en True
y el comportamiento será el descrito anteriormente.
Opcionalmente, puede definir full_oauth
en False
. En este caso, la función consulta el token que viene en la llamada entrante de la cabecera de gateway de API y lo reutiliza en la llamada saliente a Oracle Fusion Applications Cloud Service. No se genera ningún segundo token.
El siguiente fragmento de código usa la biblioteca Apache HTTP y llama a la API REST de Oracle Fusion Applications Cloud Service mediante el token de autenticación transferido.
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();
Compilar y desplegar la función
En Oracle Functions, cree una aplicación para la función y, a continuación, despliegue la función.
Definir opcionalmente una función de autenticación en Oracle Cloud Infrastructure
El gateway de API de Oracle Cloud Infrastructure soporta IDCS de forma nativa como proveedor de autenticación. Sin embargo, el gateway también permite la definición de una función a la que puede llamar. Opcionalmente, puede crear una función de autenticación personalizada mediante esta función.
La función de autenticación personalizada recibe una llamada del gateway y la transfiere. Si la función devuelve el valor true, se permite la llamada de función; al contrario, si devuelve el valor false, la solicitud se rechaza con un código de error HTTP 401. La función se proporciona en el formato de código de origen y se despliega en Funciones, a las que luego se hace referencia en el archivo de despliegue GATEWAY de API de OCI mediante su OCID. Puede detectar el OCID navegando a la función desplegada en la consola y ampliando su columna OCID. Antes de desplegar la función, debe editar el archivo ResourceServerConfig.java
; esta opción define cómo se conecta la función a Oracle Identity Cloud Service y cuál es la aplicación Oracle Identity Cloud Service OAuth.
El siguiente ejemplo de función evita la codificación fija de valores confidenciales como el secreto de cliente. En las cuatro líneas debajo del comentario // KMS Key for IDCS Client Secret
, el código descifra el secreto de OAuth mediante la función de gestión de claves de Oracle Cloud Infrastructure, Oracle Cloud Infrastructure Vault. Introduzca estos valores en la consola de Oracle Cloud Infrastructure antes de desplegar la función.