Desenvolver Funções
Antes de implantar uma implantação do Gateway de API, você precisará desenvolver e implantar suas funções.
Sobre a Lógica de Negócios
O crux da implementação é colocar algum código em uma função. Esse código pode ser tão complexo quanto necessário, chamando vários pontos finais ou talvez ao executar alguma agregação. A função lógica de negócios é o código que será chamado quando necessário pelo Oracle Cloud Infrastructure API Gateway.
Neste exemplo, a API Gateway chama uma Função Oracle, que, por sua vez, consulta alguns dados do Oracle Fusion Applications Cloud Service por meio da API REST, manipula e os retorna ao usuário. Ao escrever a função em si, você pode usar qualquer estrutura adequada desejada, mas precisa saber o impacto de uma estrutura para funções sem servidor. Neste exemplo, usamos o Java como idioma e a biblioteca Apache HttpClient para estabelecer conexão com o REST Service. A biblioteca Apache foi escolhida porque é fácil usar e fácil de implementar; no entanto, no Java 11 agora temos o novo cliente HTTP que também poderia ser usado.
Você também deve evitar frameworks que instanciem muitos objetos na memória ao chamar APIs REST, porque esses objetos serão descartados em cada chamada e, portanto, reduzirão a execução da função.
Sobre a Obtenção de Nomes de Usuário e Funções
Quando uma função é chamada pelo Oracle Cloud Infrastructure API Gateway, o gateway injeta alguns metadados na chamada usando Cabeçalhos HTTP. Esses cabeçalhos são acessíveis ao usar o SDK de Funções.
Por exemplo, no seguinte snippet do código Java (extraído da classe JWTUtils
no código de exemplo fornecido com essa solução playbook), extraimos o token de autenticação, decodifique-o e depois retorne-o como parte do corpo para o chamador.
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");
O nome do usuário pode ser usado dentro da função para implementar a lógica de negócios conforme necessário. As funções não estão disponíveis no token de Autenticação, mas podem ser consultadas do Oracle Identity Cloud Service usando APIs REST.
Quando o Oracle API Gateway chama a função, vários cabeçalhos úteis também são enviados. Esses cabeçalhos podem ser lidos usando a API da função. Os cabeçalhos úteis disponíveis no Kit do Desenvolvedor de Funções incluem:
Fn-Http-Method | O método usado para chamar a função (GET/POST/PUT etc.). |
Fn-Http-Request-Url | O URL usado para chamar a função; isso inclui os parâmetros da consulta. |
Fn-Http-H-User-Agent | Os detalhes do cliente, como sistema operacional, fornecedor e versão. |
Por exemplo, usando uma combinação de Fn-Http-Method e Fn-Http-Request-Url você pode implementar um roteador em seu código para que sua função faça diferentes coisas relacionadas com base em como ela foi chamada (como PUT, PATCH etc). Essa abordagem geralmente é chamada de padrão “Serverless Service” e tem a vantagem de que o desenvolvedor tem de manter menos funções, e cada função tem um pouco roteador que determina o que ele precisa fazer.
public OutputEvent handleRequest(InputEvent rawInput, HTTPGatewayContext hctx) throws JsonProcessingException {
String httpMethod = hctx.getMethod();
String httpRequestURI = hctx.getRequestURL();
// etc
}
Sobre a Chamada Oracle Fusion Applications Cloud Service Usando um Token de Acesso de Asserção JWT
Você precisa implementar a Asserção JWT da Oracle Functions usando o sujeito no cabeçalho de Autorização recebido.
O exemplo de Função fornecido com este playbook de solução pode executar este processo de segurança usando uma biblioteca auxiliar denominada idcsOAuthAsserter
. A biblioteca auxiliar executa o fluxo completo de Asserção de OAuth executando uma troca de tokens de portador antes de chamar o Oracle Fusion Applications Cloud Service. Esta biblioteca é integrada com a Função de amostra.
A Função requer a chave privada e o certificado público para criar as asserções de usuário e cliente usadas para chamar o Oracle Identity Cloud Service para criar um novo token de acesso portador usando a Asserção JWT OAuth.
A biblioteca idcsOAuthAsserter
requer algumas propriedades que você pode definir na Configuração da Função. Todas as variáveis da tabela a seguir são obrigatórias:
Nome da configuração | Descrição | Exemplo |
---|---|---|
IDCS_URL | URL da sua instância do Oracle Identity Cloud Service | https://<sua nuvem de identidades hostname.identity.oraclecloud.com> |
CLIENT_ID | O ID do Cliente do Aplicativo Oracle Identity Cloud Service associado ao Oracle Functions e ao Oracle API Gateway | 1a2b3c4d5e6f7g8h9i01j2k3l4m5o6p7 |
KEY_ID | Alias dos certificados importados para o Aplicativo Oracle Identity Cloud Service Confiável | fnassertionkey |
ESCOPO | Este escopo deve corresponder ao recurso OAuth de destino, que é o Aplicativo Oracle Identity Cloud Service associado ao seu Oracle Fusion Applications Cloud Service | urn:opc:resource:fa:instanceid=xxxxxxxxxurn:opc:resource:consumer: all https://my_fusion_hostname:443/ |
PÚBLICO | Públicos-alvo para o processo de Asserção. Separe diversas entradas com vírgula. | myhostname.identity.oraclecloud.com, https://myfusionservice.dc1.oraclecloud.com |
IDDOMAIN | Nome do tenant da Instância Oracle Fusion Applications Cloud Service | mytenant |
A função também exigirá propriedades de configuração para acessar secrets relacionadas à asserção idcsOAuthAsserter
. A Asserção JWT exige um certificado e uma chave privada para gerar as asserções de cliente e usuário. A função recupera a área de armazenamento de chaves com o OCID especificado em V_KEYSTORE
. O alias a recuperar essas informações deve corresponder ao valor KEY_ID
na configuração. A frase-senha da área de armazenamento de chaves e da chave privada deve ser recuperada do Oracle Cloud Infrastructure Vault Secrets Service usando os OCIDs especificados em V_KS_PASS
e V_PK_PASS
.
Nome da Configuração | Descrição | Exemplo |
---|---|---|
V_KEYSTORE | Segredo que contém o conteúdo armazenado seguro da área de armazenamento de chaves | ocid1.vaultsecret.oc1.dc1. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
V_KS_PASS | Segredo que contém a senha armazenada segura da área de armazenamento de chaves | ocid1.vaultsecret.oc1.dc1. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
V_PK_PASS | Segredo que contém a senha armazenada segura da chave privada | ocid1.vaultsecret.oc1.dc1. xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
Um valor de configuração adicional suportado é a propriedade USE_CACHE_TOKEN
, que é definida como True
por default. Esta propriedade permite armazenar o token de asserção Oracle Identity Cloud Service gerado a ser reutilizado em chamadas futuras do Oracle Fusion Applications Cloud Service, desde que o token permaneça válido. O token armazenado no cache é validado antes do uso, comparando o Assunto com o token de entrada e verificando o horário de expiração para verificar se ele ainda é válido. Caso contrário, um novo token de acesso será solicitado usando a Asserção de OAuth. Esse recurso pode ser desativado definindo USE_CACHE_TOKEN
como False
.
A Função a ser implementada pode usar SecurityHelper object
da biblioteca idcsOAuthAsserter
para extrair o assunto do cabeçalho access-token
, gerar um novo token de acesso Bearer com Asserção OAuth JWT e enviar uma solicitação ao Oracle Fusion Applications Cloud Service usando o novo token de acesso como cabeçalho Authorization
.
A Função saasopportunitiesfn
na amostra de código-fonte já está integrada à biblioteca idcsOAuthAsserter
. O seguinte snippet do código está disponível no método handleRequest
da amostra de Função, que mostra como inicializar os objetos de idcsOAuthAsserter
e executar um intervalo de tokens usando a asserção com 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 que nesse snippet o objeto SecurityHelper
é inicializado com um objeto de contexto do tipo RuntimeContext
. Isso será usado para inicializar o SecurityHelper
com a configuração da Biblioteca Auxiliar idcsOAuthAsserter
.
O exemplo de Função saasopportunitiesfn
está definido para usar a região US_PHOENIX_1
, portanto, você deve alterar a região no método setOciRegion
mostrado no snippet para apontar para a região.
SecurityHelper
também tem o método extractSubFromJwtTokenHeader
que pega o objeto InputEvent
do método Função handleRequest
para extrair o token Bearer que vem no cabeçalho Authorization
do Gateway de API. Em seguida, você deverá ser capaz de recuperar um Token de Acesso como resultado da Asserção de Oracle Identity Cloud Service.
Para obter mais informações sobre o uso e a integração idcsOAuthAsserter
com uma Função, revise o arquivo README para idcsOAuthAsserter
no repositório de código com o exemplo de código que pode ser baixado que acompanha este playbook de solução.
Definir Parâmetros de Configuração
O ambiente Oracle Functions fornece uma parte muito útil da funcionalidade, onde você pode definir alguns parâmetros dentro do ambiente Oracle Cloud Infrastructure e, em seguida, fazer referência a eles a partir do código.
Nesse caso de uso, você definirá o Fusion e os URLs de token OverrideJWT e um flag chamado full_oauth
, como parâmetros usados em seu código. Para adicionar parâmetros:
Dentro do código, você pode acessar essas variáveis de configuração usando o SDK Funções usando uma anotação Java especial (@FnConfiguration
) e acessando os parâmetros por meio da variável 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);
}
Além disso, como essa solução usa a biblioteca auxiliar idcsOAuthAsserter
, você precisa fornecer na Configuração da Função as variáveis específicas descritas na seção anterior para usar a asserção do Oracle Identity Cloud Service OAuth para trocar tokens de acesso. Como esse processo requer várias configurações obrigatórias, sugerimos que você defina sua configuração de Função usando a abordagem de arquivo yaml. Por exemplo:
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>
Passar Token de Autenticação do Usuário para Fusion Applications
Sua função precisa tratar do token de autenticação do usuário para interações seguras de API REST.
Quando a função for chamada, ela também receberá uma variável de cabeçalho “autorização” que conteria um token de autenticação. Este token é gerado pelo servidor de identidades do aplicativo de chamada, que é o mesmo servidor de identidades que sua função de gateway de API do Oracle Cloud Infrastructure está usando para validar a solicitação.
A abordagem descrita neste livro de solução o incentiva você a usar a Asserção JWT do Oracle Identity Cloud Service OAuth para fazer o intercâmbio de tokens usando a biblioteca auxiliar idcsOAuthAsserter
. Isso fornece uma camada de segurança adicional para a chamada do Oracle Functions para o Oracle Fusion Applications Cloud Service. Conforme mostrado no diagrama de arquitetura, a Função com consultas de Asserção JWT do OAuth para o token que vem na chamada de entrada do cabeçalho do Gateway de API e usa para ser escalada para outro token durante o processo de Asserção com o Oracle Identity Cloud Service. Esse novo token será usado na chamada de saída para seu servidor de destino ( Oracle Fusion Applications Cloud Service ) e ele ( Oracle Fusion Applications Cloud Service ) executará a chamada como o usuário no Oracle Visual Builder.
Na função de amostra fornecida (saasopportunitiesfn
), há uma configuração denominada full_oauth
, que, por padrão, é definida como True
e o comportamento será descrito acima.
Como opção, você pode definir full_oauth
como False
. Nesse caso, a Função consulta o token que vem na chamada de entrada do cabeçalho do Gateway de API e o reutiliza na chamada de saída para o Oracle Fusion Applications Cloud Service. Nenhum segundo token foi gerado.
O snippet de código a seguir usa a biblioteca HTTP Apache e chama a API REST Oracle Fusion Applications Cloud Service usando o token de autenticação informado.
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 e Implantar sua Função
No Oracle Functions, crie um aplicativo para sua função e, em seguida, implante a função.
Como opção, Definir uma Função de Autenticação no Oracle Cloud Infrastructure
O gateway da API Oracle Cloud Infrastructure suporta nativamente o IDCS como um provedor de autenticação. No entanto, o gateway também permite a definição de uma função que ele pode chamar. Opcionalmente, você pode criar uma função de autenticação personalizada usando esse recurso.
A função de autenticação personalizada recebe uma chamada do gateway, transmitindo-a o cabeçalho de autorização de entrada. Se a função retornar verdadeiro, a chamada de função será permitida; principalmente se retornar falso, a solicitação será rejeitada com um código de erro HTTP 401. A função é fornecida no formato do código de origem e implantada nas Funções, que são referenciadas no arquivo de implantação GATEWAY da API do OCI por meio de seu OCID. Você pode descobrir o OCID navegando até a função implantada na console e expandindo sua coluna OCID. Para que a função possa ser implantada, você precisa editar o arquivo ResourceServerConfig.java
; isso define como a função se conecta ao Oracle Identity Cloud Service e qual aplicativo Oracle Identity Cloud Service OAuth é usado.
O exemplo de função abaixo evita a codificação de valores confidenciais como o segredo do cliente. Nas quatro linhas abaixo do comentário // KMS Key for IDCS Client Secret
, o código decriptografa o segredo OAuth usando a funcionalidade de gerenciamento de chaves Oracle Cloud Infrastructure, Oracle Cloud Infrastructure Vault. Você insere esses valores na console do Oracle Cloud Infrastructure antes de implantar a função.