#OAuth2

0 Seguidores · 21 Postagens

Artigos e perguntas sobre autenticação OAuth2.

Anúncio Danusa Calixto · Abr. 25, 2025

O InterSystems IRIS 2025.2.0 apresenta vários recursos para melhorar a experiência do usuário na configuração do OAuth2.

- OAuth2 agora é um tipo de autenticação nativa e pode ser facilmente habilitado para seus serviços e aplicativos web. Anteriormente, o OAuth2 era um tipo de autenticação delegada.

- Agora você pode criar servidores de recursos com a nova classe OAuth2.ResourceServer, que simplifica significativamente a configuração do servidor de recursos. Anteriormente, os servidores de recursos eram instâncias de OAuth2.Client.

0
0 26
Artigo Heloisa Paiva · Mar. 5, 2025 6m read

O que é JWT?

JWT (JSON Web Token) é um padrão aberto (RFC 7519) que oferece um método leve, compacto e auto-contido para transmitir informações de forma segura entre duas partes. É comumente usado em aplicações web para autenticação, autorização e troca de informações.

Um JWT é tipicamente composto por três partes:

1. Cabeçalho JOSE (JSON Object Signing and Encryption) 
2. Payload (Carga útil)
3. Assinatura

Essas partes são codificadas no formato Base64Url e concatenadas com pontos (.) separando-as.

Estrutura de um JWT

Cabeçalho

{ "alg": "HS256", "typ": "JWT"}

Payload

0
0 43
Artigo Heloisa Paiva · Set. 28, 2024 1m read

Baseado num ótimo exemplo e workshop construído por @Luis Angel Pérez Ramos (veja artigos relacionados e o Open Exchange app relacionado), que incluiu um container local InterSystems for Health (e setup desejado), essa amostra apresentada aqui, adaptada do workshop para usar o InterSystems Cloud FHIR Server, e suas definições relacionadas.

0
0 35
Artigo Heloisa Paiva · Set. 20, 2024 4m read

Nós concluímos essa série de artigos SMART On FHIR com Auth0 e InterSystems FHIR Repository revisando nossa aplicação desenvolvida em Angular 16.

Vamos relembrar como foi definida a arquitetura da nossa solução:

Nossa aplicação front-end corresponde à segunda coluna e como você pode ver ela tem duas funções:

  1. Redirecionar a requisição de login para Auth0 e receber a resposta
  2. Enviar e receber a resposta de requisições via REST enviadas ao servidor FHIR

Angular

0
0 42
Artigo Heloisa Paiva · Set. 18, 2024 7m read

No último artigo nós apresentamos a arquitetura do nosso projeto SMART On FHIR, então agora é o momento de colocar a mão na massa e começar a configurar os elementos que vamos precisar. 

Vamos começar com Auth0.

Configuração AUTH0

Vamos começar criando uma conta Auth0 com um email válido. Uma vez registrada, vamos criar nossa primeira aplicação e faremos isso do menu a esquerda:

Em nosso exemplo, a aplicação será do tipo Single Page Web Application, como é uma aplicação desenvolvida em Angular 16. Selecionamos esta opção e clicamos em Create.

Na próxima pagina devemos definir os seguintes campos:

0
0 34
Artigo Heloisa Paiva · Set. 14, 2024 4m read

Introdução

Eu recentemente participei no "mão na massa" fantasticamente organizado pelo @Patrick Jamieson no qual uma aplicação Angular foi configurada junto com um servidor IRIS FHIR seguindo os protocolos definidos pelo SMART On FHIR e eu o achei muito interessante, então decidi desenvolver a minha própria aplicação Angular e então usar o que aprendi e publicar na comunidade.

SMART On FHIR

Vamos ver o que o Google nos conta sobre o SMART On FHIR:

0
0 70
Artigo Danusa Calixto · Abr. 4, 2024 3m read

Neste artigo, vou explicar como autenticar, autorizar e auditar por código usando o web app CSP ao ativar/desativar e autenticar/remover autenticação de qualquer web app.

  • A demonstração online está disponível em cloud https://dappsecurity.demo.community.intersystems.com/csp/user/index.csp (SuperUser | SYS)
  • Recomendo assistir o vídeo antes de continuar https://www.youtube.com/watch?v=qFRa3njqDcA

Layout do aplicativo
 

Vamos começar com a autenticação

A autenticação verifica a identidade de qualquer usuário ou outra entidade que tenta se conectar ao InterSystems IRIS®. Como se costuma dizer, a autenticação é como você prova que é quem diz ser.

Há várias maneiras diferentes que um usuário pode ser autenticado. Cada uma é conhecida como um mecanismo de autenticação. O InterSystems IRIS aceita vários mecanismos de autenticação:

  • Kerberos — o protocolo Kerberos foi criado para oferecer uma autenticação segura a serviços em uma rede desprotegida. O Kerberos usa tickets para autenticar um usuário e evita a troca de senhas na rede.
  • Baseado no sistema operacional — a autenticação baseada no SO usa a identidade do sistema operacional para cada usuário identificar esse usuário para o InterSystems IRIS.
  • Autenticação da instância — com esse tipo de autenticação, o InterSystems IRIS solicita uma senha ao usuário e compara um hash de senhas fornecidas com um valor armazenado.
  • Lightweight Directory Access Protocol (LDAP) — com esse protocolo, o InterSystems IRIS autentica o usuário com base nas informações em um repositório central, conhecido como servidor LDAP.
  • Autenticação delegada — possibilita a criação de mecanismos de autenticação personalizados. O desenvolvedor do aplicativo controla totalmente o conteúdo do código de autenticação delegada.

Estou usando a Autenticação da instância. Para a criação do Usuário, podemos usar o seguinte comando objectscript  :

  &sql(CREATE USER TestUser IDENTIFY BY demo)

Criamos TestUser com a senha da demonstração


Auditoria

Ao criar o registro do usuário, também é adicionado o banco de dados de auditoria usando o comando objectscript abaixo:

Do $SYSTEM.Security.Audit("%System","%Security","UserChange","User:TestUser | Password:demo","Audit Log inserted from Data_APP_Security")


Leia a documentação relacionada (Guia de auditoria): https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AAUDIT


Autorização

Depois que a autenticação for concluída, precisamos criar funções, conceder Privilégios às funções e, em seguida, vincular as funções aos usuários (Autorização). Faremos isso em três etapas

Etapa 1: Crie uma função usando o seguinte comando objectscript. Estamos criando uma função ReadWrite

&sql(CREATE ROLE ReadWrite)


Etapa 2: conceda Privilégios SELECT,UPDATE,INSERT NA tabela à Função. Estamos atribuindo privilégios da tabela scw.Patient à função ReadWrite

&sql(GRANT SELECT,UPDATE,INSERT ON scw.Patient TO ReadWrite)


Etapa 3: Conceda a Função ao usuário. Estamos atribuindo a função ReadWrite ao TestUser 

&sql(GRANT ReadWrite To TestUser)

Ativar/desativar web app

Podemos ativar ou desativar o web app usando o seguinte código objectscript

New $Namespace
Set $Namespace = "%SYS"
Set App = ##class(Security.Applications).%OpenId("/terminal")
Set App.Enabled=0
Do App.%Save()

"/terminal" aqui é o nome do aplicativo. O aplicativo pode ser desativado definindo "App.Enabled" como 0 e ativado definindo o valor como 1


Autenticar/remover autenticação de web app

Podemos definir a autenticação usando o seguinte código objectscript

New $Namespace
Set $Namespace = "%SYS"
Set App = ##class(Security.Applications).%OpenId("/terminal")
Set App.AutheEnabled=0
Do App.%Save()

"/terminal" aqui é o nome do aplicativo. A autenticação pode ser definida usando a propriedade "App.AutheEnabled". Os seguintes valores numéricos podem ser definidos

property AutheEnabled as Security.Datatype.Authentication [ InitialExpression = 64 ];

Authentication and Session mechanisms enabled (CSP Only). Bit 2 = AutheK5API Bit 5 - AutheCache Bit 6 = AutheUnauthenticated Bit 11 = AutheLDAP Bit 13 = AutheDelegated Bit 14 = LoginToken Bit 20 = TwoFactorSMS Bit 21 = TwoFactorPW

Obrigado

0
0 101
Artigo Danusa Calixto · Set. 1, 2023 5m read

Olá, comunidade!

Com certeza, todos vocês já ouviram algo sobre a Salesforce – a empresa e seu software. Neste artigo, vamos nos concentrar na conectividade com o software CRM – Salesforce CRM. De uma forma muito genérica, o Salesforce CRM tem a capacidade de gerenciar as interações com os clientes de uma organização por meio de vários métodos, como telefonemas, consultas por e-mail, comunidades, mídias e redes sociais. Diz-se que o Salesforce lida com todos os relacionamentos com os clientes - com foco nos processos de vendas, suporte e marketing. Este serviço/software está disponível na nuvem.

Como seria bom se pudéssemos nos conectar ao Salesforce a partir do nosso ambiente InterSystems IRIS ou qualquer outro produto InterSystems.

A verdade é que acessar os objetos (dados) do Salesforce é bastante simples e intuitivo. Este artigo é dedicado a descrever as etapas necessárias para estabelecer conectividade e acessar os dados disponíveis no Salesforce.

APIs do Salesforce

O Salesforce tem uma infinidade de APIs. Para nós, e ao longo deste artigo, vamos nos dedicar à API REST. Essa API fornece uma interface de serviços da Web baseada em REST - avançada, prática e simples para interagir com o Salesforce. Suas vantagens incluem a facilidade de integração e desenvolvimento, sendo uma excelente opção tecnológica para uso com aplicativos móveis e projetos Web. Para determinados projetos, a API REST pode ser usada com outras APIs do Salesforce. Para obter mais informações sobre as APIs do Salesforce, você pode consultar aqui.

Configuração no Salesforce

Apesar de não ser o objetivo deste artigo, deixo aqui o link para o tutorial de configuração do endpoint REST no Salesforce - é o guia que está na base deste artigo. De forma bem resumida, as etapas necessárias são:

Etapa 1: Inscrever-se no Salesforce Developer Edition fornece uma solução fácil e gratuita para você usar o Salesforce para testes e desenvolvimento.

Etapa 2: Configurar autenticação para enviar solicitações com sucesso, a API REST requer um token de acesso obtido por meio de autenticação. É verdade que é possível criar e autenticar seu próprio ConnectedApp (aplicativo conectado). No entanto, usaremos o CLI do Salesforce por conveniência. O CLI do Salesforce é um ConnectedApp que pode ser autenticado e não requer nenhum trabalho para configurar. Para fazer isso, você precisará acessar o console do Salesforce:

 

Navegue até Aplicativos -> Gerenciador de aplicativos -> Criar ConnectedApp

 

Os parâmetros de configuração são:

  • Nome do aplicativo conectado
  • Nome da API           
  • E-mail de contato
  • Ativar configurações OAuth: sim
  • URL de retorno de chamada: https://localhost
  • Escopos OAuth selecionados: acesso total (completo)
  • Gravar/Continuar (isso pode levar até 10 minutos) 
  • Assim que a geração do endpoint terminar, teremos nosso ConsumerKey e ConsumerSecret - é necessário copiar e salvar.

    Etapa 3: Falta uma última configuração no Salesforce.

    Vá para Configuração -> Ferramentas da plataforma -> Aplicativos -> Aplicativos conectados -> Gerenciar aplicativos conectados

    Editar recursos do aplicativo: 

    No nosso ConnectedApp, temos que editar as políticas (editar políticas) e alterar os seguintes parâmetros conforme anexo:

  • Usuários permitidos: todos os usuários podem se autoautorizar
  • Relaxamento de IP: relaxe as restrições de IP para dispositivos ativados
  • A partir do InterSystems IRIS:

    Etapa 1: Usaremos o Python incorporado para nossa conexão com o Salesforce. A primeira coisa que devemos fazer é instalar o pacote necessário para estabelecer as conexões HTTP – Solicitações. Para instalá-lo em um container é necessário:

    $ pip3 install --target /usr/irissys/mgr/python requests

     

    Etapa 2: A seguir, temos uma classe de exemplo com código de amostra para acessar os recursos do Salesforce. Neste caso, é feito um pedido para obter os objetos disponíveis. Antes de experimentar este exemplo, certifique-se de preencher os pré-requisitos e obter um token de acesso na configuração do Salesforce.

    Class salesforce.PyConnTest
    {
    
    ClassMethod connTest() [ Language = python ]
    {
        import requests
        
        #create access token
        CONSUMER_KEY='XXXXXXXXXX'
        CONSUMER_SECRET='XXXXXXXXXX'
        DOMAIN_NAME='https://intersystems4-dev-ed.develop.my.salesforce.com'
        USERNAME='mymail@domain.com'
        PASSWORD='mypassword'
        json_data={
            'grant_type': 'password',
            'client_id': CONSUMER_KEY,
            'client_secret': CONSUMER_SECRET,
            'username': USERNAME,
            'password': PASSWORD
        }
    
        response_access_token=requests.post(DOMAIN_NAME + '/services/oauth2/token, data=json_data)
        print(response_access_token.status_code)
        print(response_access_token.reason)
        print(response_access_token.json())
    
        if response_access_token.status_code == 200:
            access_token_id=response_access_token.json()['access_token']
            print('access token created')
    
        #retrieve available objects
        headers={
            'Authorization: 'Bearer ' + access_token_id 
        }
        response_sObject=requests.get(DOMAIN_NAME + '/services/data/v53.0/sobjects', headers=headers)
        print(response_sObject.reason)
        print(response_sObject.json())
    }
    
    }
    

    Os parâmetros mais relevantes são:

  • grant_type: nestes exemplos usamos "senha".
  • client_id: é o identificador público do aplicativo. Ele é gerado quando o ConnectedApp é criado.  
  • client_secret: é um segredo conhecido apenas pelo servidor de Autorização e pelo App. Ele é gerado quando o ConnectedApp é criado. 
  • username: usuário registrado no Salesforce
  • password: senha do usuário do Salesforce.
  • Essa configuração básica estabelece a conexão entre o InterSystems IRIS (ou qualquer outro produto InterSystems) e o Salesforce. Este artigo é baseado no guia rápido do Salesforce e é dedicado à API REST do Salesforce.  

    0
    0 568
    Artigo Danusa Calixto · Ago. 8, 2023 11m read

    Prefácio

    O InterSystems IRIS a partir da versão 2022.2 inclui uma funcionalidade reformulada para JSON web tokens (JWTs). Antes localizada no pacote da classe %OAuth2, a classe JWT, junto com as outras classes da Web JSON (JWCs), agora está em %Net.JSON. Essa migração ocorreu para modularizar as JWCs. Antes, eles estavam estreitamente ligados à implementação do framework OAuth 2.0. Agora, eles podem ser mantidos e usados separadamente.

    Observação: para a compatibilidade com as versões anteriores, as classes ainda existem no pacote %OAuth2, mas a codebase agora usa %Net.JSON.

    O objetivo deste artigo é servir como uma espécie de referência para as JWCs porque, ao tentar escrever uma documentação, não encontrei nenhuma fonte com informações abrangentes sobre todas elas e como se relacionam entre si. Espero que este artigo seja essa fonte.

    Prólogo

    O que são as JWCs?

    As classes da Web JSON são os protocolos da Web que usam estruturas de dados baseadas em JSON. Elas são úteis para a autorização e a troca de informações, como OAuth 2.0 e OpenID Connect.

    No momento, o InterSystems IRIS 2022.2+ é compatível com sete classes em %Net.JSON: (clique para abrir a definição)

    > JSON Object Signing and Encryption (JOSE) Um conjunto de padrões para assinar e criptografar dados usando estruturas de dados baseadas em JSON. Isso inclui JWT, JWS, JWE, JWA, JWK e JWKS.
    > JSON Web Token (JWT) Uma maneira compacta e segura para o URL de representar informações transferidas entre duas partes que podem ser assinadas digitalmente, criptografadas ou ambos.
    > JSON Web Signature (JWS) Uma JWS representa o conteúdo assinado usando estruturas de dados baseadas em JSON. O JWA define os algoritmos de assinatura e verificação para a JWS. Ou seja, um JWT assinado.
    > JSON Web Encryption (JWE) Uma JWE representa o conteúdo criptografado usando estruturas de dados baseadas em JSON. A JWA define os algoritmos de criptografia e descriptografia para a JWE. Ou seja, um JWT criptografado.
    > JSON Web Algorithms (JWA) Um JWA define um conjunto de algoritmos criptográficos e identificadores usados com as classes JWS, JWE e JWK.
    > JSON Web Key (JWK) Uma JWK representa uma chave criptográfica usada como entrada para os algoritmos definidos na classe JWA.
    > JSON Web Key Set (JWKS) Um JWKS é um conjunto de JWKs

    O diagrama a seguir demonstra a relação entre as JWCs, conforme definido abaixo: Fluxo de JWCs

    Vamos analisar cada parte na seção a seguir.

    Um estudo do JWT

    Um JSON web token (JWT) é uma maneira compacta e segura para o URL de representar informações transferidas entre duas partes que podem ser assinadas digitalmente, criptografadas ou ambos.

    Há dois tipos de JWTs:

    • JWS
    • JWE

    Uma JWS é um JWT assinado e uma JWE é um JWT criptografado. Na linguagem corrente, falamos "JWT" ou "JWT criptografado". Para JWTs, o padrão é que sejam assinados, ainda que possam não ser assinados (JWTs não seguros).

    Mas vamos voltar um pouco — o que é uma informação? É apenas um pedaço de informação representado em um par de chave/valor que um cliente está afirmando ser verdadeiro. Por exemplo, pode ser uma informação sobre um cliente que está tentando fazer login de um determinado local. O seguinte objeto JSON contém três informações (username, location, and admin):

    {
        "username": "persephone",
        "location": "underworld",
        "admin": "true"
    }
    

    Então, os JWTs transferem informações assim entre duas partes, como cliente e servidor. No entanto, se apenas essas informações fossem transferidas, não haveria garantia de que ninguém adulterou ou viu o conteúdo, além do destinatário. Nossa mensagem não teria integridade ou confidencialidade. Felizmente, os JWTs fornecem uma maneira opcional de garantia com ambos os padrões JSON web signature (JWS) e JSON web encryption (JWE). Seja uma JWS ou JWE, um JWT tem várias partes.

    JSON Web Signature (JWS)

    Um JWT não criptografado e assinado (portanto, chamado de JWS) possui três partes:

    1. Header (cabeçalho)
    2. Payload (carga útil)
    3. Signature (assinatura)

    Cada parte é um objeto JSON. Se você fizer a codificação Base64URL de cada parte e concatená-las com um ponto (.) entre elas, você terá um JWT (header.payload.signature).

    Vamos analisar cada parte.

    Cabeçalho

    O cabeçalho de uma JWS consiste em metadados sobre o tipo de token e, se especificado, o JSON web algorithm (JWA) necessário para a validação da assinatura do token. Por exemplo:

    {
      "alg": "HS256",
      "typ": "JWT"
    }
    

    Codifique o texto abaixo em Base64URL e você terá a primeira parte de um JWT!

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    

    Para resumir, o cabeçalho contém o JWA e o tipo do token.

    Carga útil

    A segunda parte de uma JWS é a carga útil. Ela contém as informações. Usando o exemplo anterior, a carga útil pode ser o seguinte:

    {
        "username": "persephone",
        "location": "underworld",
        "admin": "true"
    }
    

    Depois de codificar em Base64URL, obtemos isto:

    eyJ1c2VybmFtZSI6InBlcnNlcGhvbmUiLCJsb2NhdGlvbiI6InVuZGVyd29ybGQiLCJhZG1pbiI6InRydWUifQ
    

    Agora, nossa JWS está desta forma:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InBlcnNlcGhvbmUiLCJsb2NhdGlvbiI6InVuZGVyd29ybGQiLCJhZG1pbiI6InRydWUifQ
    

    Para resumir, a carga útil contém as informações que você quer transmitir.

    Assinatura

    A terceira parte de uma JWS é a assinatura. Você pega o JWT até o momento (o cabeçalho e a carga útil criptografados), um segredo [também chamado de chave privada ou JSON web key (JWK)], o algoritmo especificado no JWA e assina isso. Desta forma:

    HMACSHA256(
      base64UrlEncode(header) + "." +
      base64UrlEncode(payload),
      secret)
    

    Usando o segredo/valor da JWK thecatsmeow, nossa JWS ficará assim no final:

    eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InBlcnNlcGhvbmUiLCJsb2NhdGlvbiI6InVuZGVyd29ybGQiLCJhZG1pbiI6InRydWUifQ.KAZcjC9tqRV4DunI3sSma3k6fvL5ntgLXe9Gl7hKg5o
    

    Para resumir, a assinatura contém a validação da integridade.

    Abstraindo um pouco, temos:

    JSON web signature

    Você notou que eu falei...

    Talvez você tenha percebido que eu qualifiquei nosso JWT como "pode ser assinado digitalmente, criptografado ou ambos".

    Vamos falar sobre a parte da assinatura primeiro e depois abordar a criptografia na próxima seção. É possível não assinar a JWS e só ter um cabeçalho e uma carga útil (então, não é mais uma JWS, e sim um JWT não assinado e não criptografado). Isso é possível se o JWA especificado no cabeçalho para "none".

    Desta forma:

    {
      "alg": "none",
      "typ": "JWT"
    }
    

    Então, o JWT resultante seria apenas o cabeçalho criptografado em Base64URL + . + carga útil criptografada em Base64URL + .. A assinatura seria uma string vazia, então um JWT não seguro ficaria, por exemplo, desta forma:

    eyJhbGciOiJub25lIn0.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.
    

    Mas não envie JWTs não seguros, porque qualquer pessoa poderá adulterá-los e você não saberá se as informações são válidas.

    JSON Web Encryption (JWE)

    Repetindo, um JWT pode ser assinado digitalmente, criptografado ou ambos. Já discutimos as assinaturas com JWSs, então vamos seguir para a criptografia.

    Como observado acima, um JWT não criptografado e assinado (JWS) tem três partes: cabeçalho, carga útil e assinatura.

    Agora, um JWT criptografado (portanto, uma JWE) possui cinco partes:

    1. Cabeçalho protegido
    2. Chave criptografada
    3. Vetor de inicialização (IV)
    4. Carga útil/texto cifrado
    5. Tag de autenticação

    Cabeçalho protegido

    O cabeçalho protegido é a primeira parte de uma JWE. Ele não é criptografado porque o destinatário precisa saber como descriptografar o restante da JWE. Para informá-lo sobre como fazer isso, ele contém informações, como 1) o algoritmo usado para criptografar a chave de criptografia do conteúdo (CEK) e também produzir a chave criptografada e 2) o algoritmo usado para criptografar a carga útil e produzir o texto cifrado e a tag de autenticação.

    Veja a seguir um exemplo de cabeçalho protegido:

    {
      "alg":"RSA-OAEP",
      "enc":"A256GCM"
    }
    

    Ele é codificado em Base64URL para produzir o seguinte:

    eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ
    

    Chave criptografada

    A segunda parte da JWE é a chave criptografada. A chave criptografada é a forma criptografada da CEK, que é uma chave simétrica usada para criptografar a carga útil e produzir o texto cifrado e a tag de autenticação. A CEK é criptografada usando o algoritmo especificado no valor "alg" no cabeçalho protegido e na chave pública do destinatário.

    Com uma CEK de thecatsmeowmeows e uma chave pública RSA de 1024 bits gerada aleatoriamente, o valor da chave criptografada usando o algoritmo RSA-OAEP pode ser:

    X6znPIKWHnO8MhHD2scnUv7PVAo8VfxHYxmZQR0J8/rqGOB+udq8DkXd93n7S2cS3LT1Inx4qQ5J8GquQyc2xfS5n2INgKjSedYac4LBCkmpYRbRyNawK2eMEUDkcdBlqBE4NlWcAhl6X0H4AiNs7r+P8ffipvyztd51JdLoTlw=
    

    A chave criptografada é codificada em Base64URL e concatenada ao cabeçalho protegido. Portanto, temos esta JWE até o momento:

    eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.WDZ6blBJS1dIbk84TWhIRDJzY25VdjdQVkFvOFZmeEhZeG1aUVIwSjgvcnFHT0IrdWRxOERrWGQ5M243UzJjUzNMVDFJbng0cVE1SjhHcXVReWMyeGZTNW4ySU5nS2pTZWRZYWM0TEJDa21wWVJiUnlOYXdLMmVNRVVEa2NkQmxxQkU0TmxXY0FobDZYMEg0QWlOczdyK1A4ZmZpcHZ5enRkNTFKZExvVGx3PQ
    

    Vetor de inicialização (IV)

    O IV é a terceira parte da JWE. Ele é gerado aleatoriamente e codificado em Base64URL. Não precisa ser secreto, portanto não é criptografado. Por exemplo, catsarefantastic. Em seguida, codificamos em Base64URL e concatenamos com o cabeçalho protegido codificado e as partes da chave criptografada para obter:

    eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.WDZ6blBJS1dIbk84TWhIRDJzY25VdjdQVkFvOFZmeEhZeG1aUVIwSjgvcnFHT0IrdWRxOERrWGQ5M243UzJjUzNMVDFJbng0cVE1SjhHcXVReWMyeGZTNW4ySU5nS2pTZWRZYWM0TEJDa21wWVJiUnlOYXdLMmVNRVVEa2NkQmxxQkU0TmxXY0FobDZYMEg0QWlOczdyK1A4ZmZpcHZ5enRkNTFKZExvVGx3PQ.Y2F0c2FyZWZhbnRhc3RpYw
    

    Carga útil/texto cifrado

    A quarta parte de uma JWE é a carga útil/texto cifrado. É onde aninhamos o JWT. Até aqui, abordamos como proteger e depois ler esses dados após o recebimento, mas agora podemos falar sobre os dados. Tudo o que discutimos na seção de JWS é aplicável aqui. Temos nossa JWS de três partes com o cabeçalho, a carga útil e a assinatura. Em seguida, usando a CEK e o IV, criptografamos a JWS usando AES GCM e solicitamos uma saída de tag de autenticação de 128 bits.

    Um exemplo de um possível texto cifrado codificado em Base64URL:

    NjI0YjZkZTlmMGEzNjk0MTgyMTYyNTc3MmEyMjM4ZWY0MTJhMzljMzJiOGVjNzVjMzU4MGIzNTVhMGUyN2M1MWYyY2Y2OGIyYmNkODM2YmNiZjBkOGIzZjMzMmQyODBlZWZhNjBkYTQ5M2VlNjRhMTg4NmMzYTFlY2E2OGQ0NjkyOGQzNTFjOWFjODdhY2QzZDc0ZTY4OTc1MTA4NzQ0NTEyNTJhOGM5N2U3OGFkNjJhMmNmMWQwNzM5MmQwYzcyM2EzMjg5MWI2YjlmMzRkNmYxMDU5YTVlMTljZThjMTNkNzFlMjgzZWY1ZGM0ZDdmZTNhMzk1YmM2MDE5NjRmZmMwYmZlMDM2YWY1MzZmYTdiYTYzNWU3NTJmMzk1OTBhY2Y2ZWM4YjlmZjBmYzY1ZTM0M2U5YzE4OTk0ZjAyYTZlNDA0NjEzNDM1ZTVhMQ
    

    Temos esta JWE até o momento:

    eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.WDZ6blBJS1dIbk84TWhIRDJzY25VdjdQVkFvOFZmeEhZeG1aUVIwSjgvcnFHT0IrdWRxOERrWGQ5M243UzJjUzNMVDFJbng0cVE1SjhHcXVReWMyeGZTNW4ySU5nS2pTZWRZYWM0TEJDa21wWVJiUnlOYXdLMmVNRVVEa2NkQmxxQkU0TmxXY0FobDZYMEg0QWlOczdyK1A4ZmZpcHZ5enRkNTFKZExvVGx3PQ.Y2F0c2FyZWZhbnRhc3RpYw.NjI0YjZkZTlmMGEzNjk0MTgyMTYyNTc3MmEyMjM4ZWY0MTJhMzljMzJiOGVjNzVjMzU4MGIzNTVhMGUyN2M1MWYyY2Y2OGIyYmNkODM2YmNiZjBkOGIzZjMzMmQyODBlZWZhNjBkYTQ5M2VlNjRhMTg4NmMzYTFlY2E2OGQ0NjkyOGQzNTFjOWFjODdhY2QzZDc0ZTY4OTc1MTA4NzQ0NTEyNTJhOGM5N2U3OGFkNjJhMmNmMWQwNzM5MmQwYzcyM2EzMjg5MWI2YjlmMzRkNmYxMDU5YTVlMTljZThjMTNkNzFlMjgzZWY1ZGM0ZDdmZTNhMzk1YmM2MDE5NjRmZmMwYmZlMDM2YWY1MzZmYTdiYTYzNWU3NTJmMzk1OTBhY2Y2ZWM4YjlmZjBmYzY1ZTM0M2U5YzE4OTk0ZjAyYTZlNDA0NjEzNDM1ZTVhMQ
    

    Tag de autenticação

    A tag de autenticação é a parte final da JWE. É um resultado do texto cifrado (JWS aninhada criptografada). A tag de autenticação recebida ao criptografar o texto cifrado na última seção é:

    9f19e30efeddf20f5232b76f07c755ac
    

    Codificamos em Base64URL e concatenamos com a JWE para obter a JWE finalizada como:

    eyJhbGciOiJSU0EtT0FFUCIsImVuYyI6IkEyNTZHQ00ifQ.WDZ6blBJS1dIbk84TWhIRDJzY25VdjdQVkFvOFZmeEhZeG1aUVIwSjgvcnFHT0IrdWRxOERrWGQ5M243UzJjUzNMVDFJbng0cVE1SjhHcXVReWMyeGZTNW4ySU5nS2pTZWRZYWM0TEJDa21wWVJiUnlOYXdLMmVNRVVEa2NkQmxxQkU0TmxXY0FobDZYMEg0QWlOczdyK1A4ZmZpcHZ5enRkNTFKZExvVGx3PQ.Y2F0c2FyZWZhbnRhc3RpYw.NjI0YjZkZTlmMGEzNjk0MTgyMTYyNTc3MmEyMjM4ZWY0MTJhMzljMzJiOGVjNzVjMzU4MGIzNTVhMGUyN2M1MWYyY2Y2OGIyYmNkODM2YmNiZjBkOGIzZjMzMmQyODBlZWZhNjBkYTQ5M2VlNjRhMTg4NmMzYTFlY2E2OGQ0NjkyOGQzNTFjOWFjODdhY2QzZDc0ZTY4OTc1MTA4NzQ0NTEyNTJhOGM5N2U3OGFkNjJhMmNmMWQwNzM5MmQwYzcyM2EzMjg5MWI2YjlmMzRkNmYxMDU5YTVlMTljZThjMTNkNzFlMjgzZWY1ZGM0ZDdmZTNhMzk1YmM2MDE5NjRmZmMwYmZlMDM2YWY1MzZmYTdiYTYzNWU3NTJmMzk1OTBhY2Y2ZWM4YjlmZjBmYzY1ZTM0M2U5YzE4OTk0ZjAyYTZlNDA0NjEzNDM1ZTVhMQ.OWYxOWUzMGVmZWRkZjIwZjUyMzJiNzZmMDdjNzU1YWM
    

    Vamos abstrair a codificação em Base64URL e analisar a visão geral de alto nível de uma JWE:

    JSON web encryption

    Observações sobre os termos

    Em busca de clareza, em vez de usar alguns nomes de classes da Web JSON, dei preferência para os nomes descritivos. Especificamente, JWK/JWKS em vez de chaves públicas, criptográficas, de criptografia, etc. A chave usada para a criptografia ou assinatura é uma JSON web key (JWK) e o conjunto delas (a chave simétrica e os pares de chaves assimétricas) é um JSON web key set (JWKS).

    Queria fazer uma pausa para mencionar isso e retomar a terminologia. Um JWT é uma JWS ou JWE. Os algoritmos usados em uma JWS/JWE são definidos no JWA. As chaves usadas como entrada para os algoritmos no JWA são JWKs, armazenadas como um conjunto JWKS.

    E o que é JOSE? JOSE é a coleção de padrões. Assim como temos bando para corvos ou gataria para gatos, temos JOSE para os padrões da Web JSON.

    Conclusão

    Espero que este artigo seja um bom ponto de referência para quem quer trabalhar com as classes da Web JSON (JWCs).

    As JWCs têm três casos de uso diferentes:

    1. Autenticação
    2. Autorização
    3. Troca de informações

    No InterSystems IRIS 2022.2+, você pode configurar o OAuth 2.0 para usar JWTs. Isso está descrito no OAuth 2.0 e OpenID Connect. Seu código personalizado pode usar as JWCs conforme definido no %Net.JSON para esses casos de uso.

    Me avise se você achou este artigo útil!

    0
    0 82
    Artigo Davi Massaru Teixeira Muta · Jun. 13, 2023 4m read

    #Introdução

    Neste artigo, vamos explorar como integrar uma conta de e-mail do Outlook Exchange com oAuth 2.0 na plataforma Intersystems IRIS 2020. Embora essa tarefa possa parecer simples. No exemplo explorado, utilizamos o código da versão 2022 (você pode baixar a versão de avaliação) e adaptamos para a versão 2020. Embora seja viável atualizar entre as versões com o instalador IRIS 2022, isso leva semanas de testes antes de fazer a alteração em produtividade. Como a integração não podia esperar, decidimos pegar componentes do IRIS 2022 e copiá-los/adaptá-los para a versão 2020.

    Para aqueles que não sabem, a Microsoft descontinuou a autenticação básica das contas do Exchange Online (https://learn.microsoft.com/pt-br/lifecycle/announcements/basic-auth-deprecation-exchange-online), dada essa situação, qualquer adaptador de correio de entrada (POP3 no caso do IRIS) ou de saída (SMTP no IRIS) agora requer autenticação OAuth 2.0 (https://learn.microsoft.com/pt-br/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth).

    Como sabemos, o OAuth é um protocolo de autorização que permite que um aplicativo, neste caso o IRIS, acesse os recursos protegidos de um usuário em um serviço online (como Facebook ou Google), sem precisar compartilhar a senha do usuário. Em vez disso, o usuário autoriza o aplicativo a acessar seus recursos por meio de um token de acesso emitido pelo serviço online. O protocolo OAuth é amplamente utilizado na autenticação e autorização de aplicativos da web e móveis.

    Ao pesquisar na documentação do IRIS, verificamos que a versão 2022 possui integrações nativas disponíveis para o OAuth.

    Porem a versão 2020 ainda não possui essas opções disponíveis:

    #Solução

    Navegando pelas classes do IRIS 2022, especificamente na versão "IRIS for Windows (x86-64) 2022.1.2 (Build 574U)", encontramos duas classes que continham o código necessário para se conectar com um token de autenticação: %Net.POP3 e EnsLib.EMail.InboundAdapter. Comparamos ambas as versões, entre o IRIS 2020 e o IRIS 2022, e começamos a realizar testes de conexão.

    Após várias tentativas, conseguimos realizar a integração criando e configurando as seguintes classes:

    TEST01.BO.REST.OAUTHTOKEN: Esta classe é responsável por fazer a solicitação REST para obter o token, neste caso, da Microsoft. Ela é chamada pelo serviço POP3 no método onTask sempre que precisa de um novo token.

    TEST01.Email.POP3: Essa classe é uma cópia da classe %Net.POP3 do IRIS 2020, mas precisamos modificá-la no método ConnectPort e adicionar um novo parâmetro chamado "AccessToken". Além disso, devemos adicionar o código (que pode ser resgatado da própria classe, porém da versão 2022) que utiliza o token para se conectar ao servidor de e-mail.

    TEST01.Email.InboundAdapter: Essa classe é uma cópia do EnsLib.EMail.InboundAdapter, mas precisamos fazer duas modificações. Primeiro, devemos modificar a propriedade MailService para "Property MailServer As TEST01.Email.POP3;". Além disso, precisamos modificar o método onTask para que ele utilize a global que armazena o token necessário para acessar a caixa de correio, token resgatado do serviço REST de autenticação (classe TEST01.BO.REST.OAUTHTOKEN).

    TEST01.Email.Service: Classe do Serviço POP3, essa classe deve ser criada normalmente no Studio com o adaptador EnsLib.EMail.InboundAdapter. Essa classe é responsável por coordenar todos os componentes criados. Devemos alterar o adaptador para TEST01.Email.InboundAdapter e modificar/adicionar o método onTask, que permite atualizar o token caso seja necessário. Para fins deste teste, deixamos um erro forçado "Prueba de Lectura" para não excluir os e-mails da conta do Exchange.

    Finalmente, conseguimos estabelecer a conexão com a caixa de correio e foi possível processá-los para uso posterior.

    link do OneDrive com as classes utilizadas: https://profcyc-my.sharepoint.com/personal/tclavero_profcyc_onmicrosoft_com/_layouts/15/onedrive.aspx?id=%2Fpersonal%2Ftclavero%5Fprofcyc%5Fonmicrosoft%5Fcom%2FDocuments%2FArticulos%2FPOP3%20oAuth%2Exml&parent=%2Fpersonal%2Ftclavero%5Fprofcyc%5Fonmicrosoft%5Fcom%2FDocuments%2FArticulos&ga=1

    Este arigo é tradução para português de (Integrando correo outlook exchange con oAuth 2.0 en Intersystems IRIS 2020)[https://es.community.intersystems.com/post/integrando-correo-outlook-exchange-con-oauth-20-en-intersystems-iris-2020]

    Artigo premiado em no "2º Concurso de Artículos Técnicos en Español" https://es.community.intersystems.com/post/segundo-concurso-de-art%C3%ADculos-t%C3%A9cnicos-en-espa%C3%B1ol

    Não foi possível adicionar a referencia a https://es.community.intersystems.com/post/integrando-correo-outlook-exchange-con-oauth-20-en-intersystems-iris-2020 em Link para o post anterior, não deixe de conferir a versão original do artigo.

    0
    1 76
    Artigo Danusa Calixto · jan 11, 2023 20m read

    Criado por Daniel Kutac, Engenheiro de vendas, InterSystems

    Parte 3. Apêndice

    Explicação sobre as classes OAUTH do InterSystems IRIS

    Na parte anterior da nossa série, aprendemos a configurar o InterSystems IRIS para atuar como um cliente OAUTH, além de um servidor de autorização e autenticação (pelo OpenID Connect). Nesta parte final da série, vamos descrever classes que implementam o framework OAuth 2.0 do InterSystems IRIS. Também vamos discutir casos de uso para métodos selecionados de classes de API.

    As classes de API que implementam o OAuth 2.0 podem ser separadas em três grupos diferentes de acordo com a finalidade. Todas as classes são implementadas no namespace %SYS. Algumas delas são públicas (por % pacote), outras não e não devem ser chamadas diretamente pelos desenvolvedores.

    Classes internas

    Estas classes pertencem ao pacote OAuth2.

    A tabela a seguir lista algumas classes de interesse (para uma lista completa de classes, consulte a Referência de Classes online da sua instância do Caché). Nenhuma dessas classes deve ser usada diretamente por desenvolvedores de aplicativos, exceto as listadas abaixo.

      <td>
        Descrição
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        OAuth2.AccessToken
      </td>
      
      <td>
        PersistentOAuth2.AccessToken armazena um token de acesso do OAuth 2.0 e as informações relacionadas. É uma cópia do cliente OAUTH do token de acesso. OAuth2.AccessToken é indexado pela combinação de SessionId e ApplicationName. Portanto, apenas um escopo pode ser solicitado para cada SessionId/ApplicationName. Se uma segunda solicitação for feita com um escopo diferente e o token de acesso ainda não tiver sido concedido, o escopo na nova solicitação se tornará o escopo esperado.
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        OAuth2.Client
      </td>
      
      <td>
        Persistente A classe OAuth2.Application descreve um cliente OAuth2 e faz referência ao servidor de autorização que usa para autorizar o aplicativo com base no RFC 6749. Um sistema cliente pode ser usado com vários servidores de autorização para diferentes aplicativos.
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        OAuth2.Response
      </td>
      
      <td>
        Página CSP É a página de destino para respostas de um servidor de autorização do OAuth 2.0 usado de código do cliente OAuth 2.0 do InterSystems IRIS. A resposta é processada aqui e redirecionada ao alvo final.
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        OAuth2.ServerDefinition
      </td>
      
      <td>
        Persistente Armazena informações do servidor de autorização usadas por um cliente OAUTH (essa instância do InterSystems IRIS). Podem ser definidas várias configurações de cliente para cada definição de servidor de autorização.
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        OAuth2.Server.AccessToken
      </td>
      
      <td>
        Persistente Os tokens de acesso são gerenciados pelo OAuth2.Server.AccessToken no servidor OAUTH. A classe armazena o token de acesso e as propriedades relacionadas. Essa classe também é o meio de comunicação entre várias partes do servidor de autorização.
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        OAuth2.Server.Auth
      </td>
      
      <td>
        Página CSP O servidor de autorização apoia o fluxo de controle de autorização para o código de autorização e os tipos de concessão implícitos conforme a especificação no RFC 6749. A classe OAuth2.Server.Auth é uma subclasse de %CSP.Page que atua como o endpoint de autorização e controla o fluxo de acordo com o RFC 6749.
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        OAuth2.Server.Client
      </td>
      
      <td>
        Persistente OAuth2.Server.Configuration é uma classe persistente que descreve os clientes registrados com esse servidor de autorização.
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        OAuth2.Server.Configuration
      </td>
      
      <td>
        Persistente Armazena a configuração do servidor de autorização. Todas as classes de configuração têm uma página correspondente no Portal de Gerenciamento de Sistemas onde os usuários preenchem os detalhes da configuração.
      </td>
    </tr>
    
    Nome da classe

    Objetos OAuth2.Client, OAuth2.ServerDefinition, OAuth2.Server.Client e OAuth2.Configuration podem ser abertos, modificados e salvos para criar ou modificar configurações sem usar a IU. Você pode usar essas classes para manipular configurações de maneira programática.

    Classes de personalização do servidor

    Estas classes pertencem ao pacote %OAuth2. O pacote contém um conjunto de classes internas — utilitários. Só descrevemos as classes que podem ser usadas por desenvolvedores. Estas classes são mencionadas na página de configuração do servidor do OAuth 2.0

      <td>
        Página CSP %OAuth2.Server.Authenticate atua como uma subclasse para todas as classes Authenticate escritas por usuários, além da classe Authenticate padrão. A classe Authenticate é usada pelo endpoint de autorização no OAuth2.Server.Auth para autenticar o usuário. Essa classe permite a personalização do processo de autenticação.Os seguintes métodos talvez sejam implementados para substituir o padrão no OAuth2.Server:·        DirectLogin – use apenas quando não quiser mostrar a página de login·        DisplayLogin – implementa o formulário de login do servidor de autorização·        DisplayPermissions – implementa o formulário com uma lista de escopos solicitados Outras personalizações de aparência e visual podem ser feitas ao modificar o CSS. Os estilos CSS são definidos no método DrawStyle. loginForm é para o formulário DisplayLogin permissionForm é para o formulário DisplayPermissions
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        %OAuth2.Server.Validate
      </td>
      
      <td>
        Página CSP Esta é a classe Validate User padrão incluída no servidor. A classe padrão usará o banco de dados do usuário da instância do Cache onde o servidor de autorização está localizado para validar o usuário. As propriedades aceitas serão o emissor (Issuer), as funções e o sub (Username). A Classe Validate User é especificada na configuração do servidor de autorização. Precisa conter um método ValidateUser, que validará uma combinação de nome de usuário/senha e retornará um conjunto de propriedades associadas ao usuário.
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        %OAuth2.Server.Generate
      </td>
      
      <td>
        Objeto registrado O %OAuth2.Server.Generate é a classe Generate Token padrão incluída no servidor. A classe padrão gerará uma string aleatória como o token de acesso opaco. A classe Generate Token é especificada na configuração do servidor de autorização. Precisa conter um método GenerateAccessToken que será usado para gerar um token de acesso com base na array de propriedades retornada pelo método ValidateUser.
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        %OAuth2.Server.JWT
      </td>
      
      <td>
        Objeto registrado O %OAuth2.Server.JWT é a classe Generate Token que cria um JSON Web Token incluído no servidor. A classe Generate Token é especificada na configuração do servidor de autorização. Precisa conter um método GenerateAccessToken que será usado para gerar um token de acesso com base na array de propriedades retornada pelo método ValidateUser.
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        %OAuth2.Utils
      </td>
      
      <td>
        Objeto registrado Esta classe implementa, entre outros, o registro de várias entidades. Um código de amostra no capítulo Personalização mostra o possível uso.
      </td>
    </tr>
    
    %OAuth2.Server.Authenticate

    A imagem a seguir mostra a seção correspondente da configuração do servidor de autorização OAuth 2.0

    Caso você use o OpenID Connect com token de identidade formatado JWT (id_token), substitua a classe Generate Token padrão %OAuth2.Server.Generate com %OAuth2.Server.JWT na configuração ou deixe a classe Generate padrão.

    Discutiremos as opções de personalização com mais detalhes mais tarde em um capítulo separado.

    Classes de API públicas

    As classes de API públicas são usadas por desenvolvedores de aplicativos para fornecer valores corretos para o fluxo de mensagens de aplicativos da Web, bem como para realizar a validação de tokens de acesso, introspecção e assim por diante.

    Essas classes são implementadas no pacote %SYS.OAuth2. A tabela lista algumas das classes implementadas.

      <td>
        Objeto registrado A classe %SYS.OAuth2.AccessToken define as operações do cliente que permitem que um token de acesso seja usado para autorizar um servidor de recursos. O token subjacente é armazenado no OAuth2.AccessToken no banco de dados CACHESYS. OAuth2.AccessToken é indexado pela combinação de SessionId e ApplicationName. Portanto, apenas um escopo pode ser solicitado para cada SessionId/ApplicationName. Se uma segunda solicitação for feita com um escopo diferente e o token de acesso ainda não tiver sido concedido, o escopo na nova solicitação se tornará o escopo esperado.
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        %SYS.OAuth2.Authorization
      </td>
      
      <td>
        Objeto registrado A classe %SYS.OAuth2.Authorization contém as operações usadas para autorizar um cliente ao obter um token de acesso. O token subjacente é armazenado no OAuth2.AccessToken no banco de dados CACHESYS. OAuth2.AccessToken é indexado pela combinação de SessionId e ApplicationName. Portanto, apenas um escopo pode ser solicitado para cada SessionId/ApplicationName. Se uma segunda solicitação for feita com um escopo diferente e o token de acesso ainda não tiver sido concedido, o escopo na nova solicitação se tornará o escopo esperado. Observe que essa classe está no CACHELIB e, portanto, disponível em qualquer lugar. No entanto, o armazenamento do token está no CACHESYS e, portanto, não está diretamente disponível para a maior parte do código.
      </td>
    </tr>
    
    <tr style="height:0px">
      <td>
        %SYS.OAuth2.Validation
      </td>
      
      <td>
        Objeto registrado A classe %SYS.OAuth2.Validation define os métodos usados para validar (ou invalidar) um token de acesso. O token subjacente é armazenado no OAuth2.AccessToken no banco de dados CACHESYS. OAuth2.AccessToken é indexado pela combinação de SessionId e ApplicationName. Portanto, apenas um escopo pode ser solicitado para cada SessionId/ApplicationName. Se uma segunda solicitação for feita com um escopo diferente e o token de acesso ainda não tiver sido concedido, o escopo na nova solicitação se tornará o escopo esperado.
      </td>
    </tr>
    
    %SYS.OAuth2.AccessToken

    Vamos analisar alguns métodos e classes desse grupo mais a fundo.

    Cada classe de aplicação cliente, que usa o token de acesso, PRECISA conferir a validade dele. Isso é feito em algum lugar no método OnPage (ou o método correspondente na página ZENMojo ou ZEN).

    Este é o fragmento de código:

     // Check if we have an access token from oauth2 server
     set isAuthorized=##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,"scope1,
         scope2",.accessToken,.idtoken,.responseProperties,.error)
    
     // Continue with further checks if an access token exists.
     // Below are all possible tests and may not be needed in all cases.
     // The JSON object which is returned for each test is just displayed.
     if isAuthorized {
        // do whatever – call resource server API to retrieve data of interest
     }
    

    Sempre que chamamos a API do servidor de recursos, precisamos fornecer o token de acesso. Isso é feito pelo método AddAccessToken da classe %SYS.OAuth2.AccessToken, veja o fragmento de código aqui

     set httpRequest=##class(%Net.HttpRequest).%New()
      // AddAccessToken adds the current access token to the request.
      set sc=##class(%SYS.OAuth2.AccessToken).AddAccessToken(
        httpRequest,,
        ..#SSLCONFIG,
        ..#OAUTH2APPNAME)
     if $$$ISOK(sc) {
        set sc=httpRequest.Get(.. Service API url …)
     }
    

    No código de amostra fornecido nas partes anteriores da nossa série, é possível ver este código no método OnPreHTTP da primeira página do aplicativo (Cache1N). Esse é o melhor local para realizar a verificação do token de acesso para a página inicial do aplicativo.

    ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ]
    {
     set scope="openid profile scope1 scope2"
        #dim %response as %CSP.Response
     if ##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,
        scope,.accessToken,.idtoken,.responseProperties,.error) {
          set %response.ServerSideRedirect="Web.OAUTH2.Cache2N.cls"
     }
     quit 1
    }

    O método IsAuthorized da classe SYS.OAuth2.AccessToken no código acima é verificar se o token de acesso válido existe e, se não existe, permite mostrar o conteúdo da página com um botão de login/link apontando para o formulário de autenticação do servidor de autorização. Caso contrário, redireciona para a segunda página, que faz o trabalho de recuperar os dados.

    Podemos, no entanto, alterar o código para que fique assim:

    ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ]
    {
     set scope="openid profile scope1 scope2"
     set sc=##class(%SYS.OAuth2.Authorization).GetAccessTokenAuthorizationCode(
        ..#OAUTH2APPNAME,scope,..#OAUTH2CLIENTREDIRECTURI,.properties)
     quit +sc
    }

    Essa variante tem um efeito diferente. Ao usar o método GetAccessTokenAuthorizationCode da classe %SYS.OAuth2.Authorization, navegamos diretamente até o formulário de autenticação do servidor de autenticação, sem mostrar o conteúdo da primeira página do nosso aplicativo.

    Isso pode ser útil nos casos em que o aplicativo da Web é invocado de um aplicativo nativo do dispositivo móvel, onde algumas informações do usuário já foram mostradas pelo aplicativo nativo (o launcher) e não há necessidade de exibir a página da Web com um botão apontando para o servidor de autorização.

    Se você usa o token JWT assinado, então precisa validar o conteúdo dele. Isso é feito pelo seguinte método:

     set valid=##class(%SYS.OAuth2.Validation).ValidateJWT(applicationName,accessToken,scope,,.jsonObject,.securityParameters,.sc)
    

    Veja a descrição detalhada dos parâmetros do método na documentação de Referência de Classes.

    Personalização

    Vamos passar algum tempo descrevendo quais opções o OAUTH oferece para a personalização da IU de autenticação/autorização.

    Suponha que a política da sua empresa exija um comportamento mais restritivo de concessão de escopo. Por exemplo, você pode executar um aplicativo de home banking que se conecta a vários sistemas bancários no seu banco. O banco só concede acesso ao escopo que contém informações sobre a conta bancária real que está sendo recuperada. Como o banco administra milhões de contas, é impossível definir o escopo estático para cada conta. Em vez disso, você pode gerar o escopo em tempo real — durante o processamento da autorização, como parte do código da página de autorização personalizada.

    Para o propósito da demonstração, precisamos adicionar mais um escopo à configuração do servidor — veja a imagem.

    Também adicionamos a referência à classe Authenticate personalizada, chamada %OAuth2.Server.Authenticate.Bank.

    Então, como é a classe de autenticação bancária? Veja uma possível variante da classe. Ela melhora os formulários de autenticação e autorização com dados fornecidos pelo usuário. As informações que fluem entre os métodos BeforeAuthenticate, DisplayPermissions e AfterAuthenticate são transmitidas pela variável de propriedades da classe %OAuth2.Server.Properties

    Class %OAuth2.Server.Authenticate.Bank Extends %OAuth2.Server.Authenticate
    {
    /// Add CUSTOM BESTBANK support for account scope.
    ClassMethod BeforeAuthenticate(scope As %ArrayOfDataTypes, properties As %OAuth2.Server.Properties) As %Status
    {
     // If launch scope not specified, then nothing to do
     If 'scope.IsDefined("account") Quit $$$OK
     // Get the launch context from the launch query parameter.
     Set tContext=properties.RequestProperties.GetAt("accno")
     // If no context, then nothing to do
     If tContext="" Quit $$$OK
        
     try {
        // Now the BestBank context should be queried.
        Set tBankAccountNumber=tContext
        // Add scope for accno. -> dynamically modify scope (no account:<accno> scope exists in the server configuration)
        // This particular scope is used to allow the same accno to be accessed via account
        // if it was previously selected by account or account:accno when using cookie support
        Do scope.SetAt("Access data for account "_tBankAccountNumber,"account:"_tBankAccountNumber)
        // We no longer need the account scope, since it has been processed.
        // This will prevent existence of account scope from forcing call of DisplayPermissions.
        Do scope.RemoveAt("account")
        
        // Add the accno property which AfterAuthenticate will turn into a response property
        Do properties.CustomProperties.SetAt(tBankAccountNumber,"account_number")
     } catch (e) {
        s ^dk("err",$i(^dk("err")))=e.DisplayString()
     }
     Quit $$$OK
    }
    
    /// Add CUSTOM BESTBANK support for account scope.
    /// If account_number custom property was added by either BeforeAuthenticate (account)
    /// or DisplayPermissions (account:accno), then add the needed response property.
    ClassMethod AfterAuthenticate(scope As %ArrayOfDataTypes, properties As %OAuth2.Server.Properties) As %Status
    {
     // There is nothing to do here unless account_number (account) or accno (account:accno) property exists
     try {
        // example of custom logging
        If $$$SysLogLevel>=3 {
         Do ##class(%OAuth2.Utils).LogServerScope("log ScopeArray-CUSTOM BESTBANK",%token)
        }
        If properties.CustomProperties.GetAt("account_number")'="" {
         // Add the accno query parameter to the response.
         Do properties.ResponseProperties.SetAt(properties.CustomProperties.GetAt("account_number"),"accno")
        }
     } catch (e) {
        s ^dk("err",$i(^dk("err")))=e.DisplayString()
     }
     Quit $$$OK
    }
    
    /// DisplayPermissions modified to include a text for BEST BANK account.
    ClassMethod DisplayPermissions(authorizationCode As %String, scopeArray As %ArrayOfDataTypes, currentScopeArray As %ArrayOfDataTypes, properties As %OAuth2.Server.Properties) As %Status
    {
     Set uilocales = properties.RequestProperties.GetAt("ui_locales")
     Set tLang = ##class(%OAuth2.Utils).SelectLanguage(uilocales,"%OAuth2Login")
     // $$$TextHTML(Text,Domain,Language)
     Set ACCEPTHEADTITLE = $$$TextHTML("OAuth2 Permissions Page","%OAuth2Login",tLang)
     Set USER = $$$TextHTML("User:","%OAuth2Login",tLang)
     Set POLICY = $$$TextHTML("Policy","%OAuth2Login",tLang)
     Set TERM = $$$TextHTML("Terms of service","%OAuth2Login",tLang)
     Set ACCEPTCAPTION = $$$TextHTML("Accept","%OAuth2Login",tLang)
     Set CANCELCAPTION = $$$TextHTML("Cancel","%OAuth2Login",tLang)
     &html<<html>>
     Do ..DrawAcceptHead(ACCEPTHEADTITLE)
     Set divClass = "permissionForm"
     Set logo = properties.ServerProperties.GetAt("logo_uri")
     Set clientName = properties.ServerProperties.GetAt("client_name")
     Set clienturi = properties.ServerProperties.GetAt("client_uri")
     Set policyuri = properties.ServerProperties.GetAt("policy_uri")
     Set tosuri = properties.ServerProperties.GetAt("tos_uri")
     Set user = properties.GetClaimValue("preferred_username")
     If user="" {
        Set user = properties.GetClaimValue("sub")
     }
     &html<<body>>
     &html<<div id="topLabel"></div>>
     &html<<div class="#(divClass)#">>
     If user '= "" {
        &html<
         <div>
         <span id="left" class="userBox">#(USER)#<br>#(##class(%CSP.Page).EscapeHTML(user))#</span>
         >
     }
     If logo '= "" {
        Set espClientName = ##class(%CSP.Page).EscapeHTML(clientName)
       &html<<span class="logoClass"><img src="#(logo)#" alt="#(espClientName)#" title="#(espClientName)#" align="middle"></span>>
     }
     If policyuri '= "" ! (tosuri '= "") {
       &html<<span id="right" class="linkBox">>
        If policyuri '= "" {
         &html<<a href="#(policyuri)#" target="_blank">#(POLICY)#</a><br>>
        }
        If tosuri '= "" {
         &html<<a href="#(tosuri)#" target="_blank">#(TERM)#</a>>
        }
       &html<</span>>
     }
     &html<</div>>
     &html<<form>>
     Write ##class(%CSP.Page).InsertHiddenField("","AuthorizationCode",authorizationCode),!
     &html<<div>>
     If $isobject(scopeArray), scopeArray.Count() > 0 {
        Set tTitle = $$$TextHTML(" is requesting these permissions:","%OAuth2Login",tLang)
       &html<<div class="permissionTitleRequest">>
        If clienturi '= "" {
         &html<<a href="#(clienturi)#" target="_blank">#(##class(%CSP.Page).EscapeHTML(clientName))#</a>>
        } Else {
         &html<#(##class(%CSP.Page).EscapeHTML(clientName))#>
        }
       &html<#(##class(%CSP.Page).EscapeHTML(tTitle))#</div>>
        Set tCount = 0
        Set scope = ""
        For {
         Set display = scopeArray.GetNext(.scope)
         If scope = "" Quit
         Set tCount = tCount + 1
         If display = "" Set display = scope
         Write "<div class='permissionItemRequest'>"_tCount_". "_##class(%CSP.Page).EscapeHTML(display)_"</div>"
        }
     }
    
     If $isobject(currentScopeArray), currentScopeArray.Count() > 0 {
        Set tTitle = $$$TextHTML(" already has these permissions:","%OAuth2Login",tLang)
       &html<<div>>
       &html<<div class="permissionTitleExisting">>
        If clienturi '= "" {
         &html<<a href="#(clienturi)#" target="_blank">#(##class(%CSP.Page).EscapeHTML(clientName))#</a>>
        } Else {
         &html<#(##class(%CSP.Page).EscapeHTML(clientName))#>
        }
       &html<#(##class(%CSP.Page).EscapeHTML(tTitle))#</div>>
        Set tCount = 0
        Set scope = ""
        For {
         Set display = currentScopeArray.GetNext(.scope)
         If scope = "" Quit
         Set tCount = tCount + 1
         If display = "" Set display = scope
         Write "<div class='permissionItemExisting'>"_tCount_". "_##class(%CSP.Page).EscapeHTML(display)_"</div>"
        }
       &html<</div>>
     }
    
     /*********************************/
     /*  BEST BANK CUSTOMIZATION      */
     /*********************************/
     try {
        If properties.CustomProperties.GetAt("account_number")'="" {
         // Display the account number obtained from account context.
         Write "<div class='permissionItemRequest'><b>Selected account is "_properties.CustomProperties.GetAt("account_number")_"</b></div>",!
    
         // or, alternatively, let user add some more information at this stage (e.g. linked account number)
         //Write "<div>Account Number: <input type='text' id='accno' name='p_accno' placeholder='accno' autocomplete='off' ></div>",!
        }
     } catch (e) {
        s ^dk("err",$i(^dk("err")))=e.DisplayString()
     }
    
     /* original implementation code continues here... */
     &html<
       <div><input type="submit" id="btnAccept" name="Accept" value="#(ACCEPTCAPTION)#"/></div>
       <div><input type="submit" id="btnCancel" name="Cancel" value="#(CANCELCAPTION)#"/></div>
        >
     &html<</form>
     </div>>
     Do ..DrawFooter()
     &html<</body>>
     &html<<html>>
     Quit 1
    }
    
    /// For CUSTOM BESTBANK we need to validate that patient entered,
    /// ! javascript in this method is only needed when we let user enter some addtional data
    /// within DisplayPermissions method !
    ClassMethod DrawAcceptHead(ACCEPTHEADTITLE)
    {
     &html<<head><title>#(ACCEPTHEADTITLE)#</title>>
     Do ..DrawStyle()
     &html<
     <script type="text/javascript">
     function doAccept()
     {
        var accno = document.getElementById("accno").value;
        var errors = "";
        if (accno !== null) {
         if (accno.length < 1) {
           errors = "Please enter account number name";
         }
        }
        if (errors) {
         alert(errors);
         return false;
        }
        
        // submit the form
        return true;
     }
     </script>
     >
     &html<</head>>
    }
    
    }

    Como você pode ver, a classe %OAuth2.Server.Properties contém várias arrays, que são passadas. São elas:

    ·        RequestProperties — contém parâmetros da solicitação de autorização

    ·        CustomProperties — contêiner para a troca de dados entre o mencionado acima

    ·        ResponseProperties — contêiner para as propriedades serem adicionadas ao objeto de resposta JSON a uma solicitação de token

    ·        ServerProperties — contém propriedades compartilhadas que o servidor de autorização expõe para o código de personalização (por exemplo, logo_uri, client_uri, etc…)

    Além disso, ela contém várias propriedades de "declarações", que são usadas para especificar quais declarações devem ser retornadas pelo servidor de autorização.

    Para chamar essa página de autenticação corretamente, modificamos nosso código inicial da página do cliente para que fique assim:

     set scope="openid profile scope1 scope2 account"
     // this data comes from application (a form data or so...) and sets a context for our request
     // we can, through subclassing the Authenticate class, display this data to user so he/she can decide
     // whether to grant access or not
     set properties("accno")="75-452152122-5320"
     set url=##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint(
       ..#OAUTH2APPNAME,
        scope,
       ..#OAUTH2CLIENTREDIRECTURI,
        .properties,
       .isAuthorized,
        .sc)
     if $$$ISERR(sc) {
        write "GetAuthorizationCodeEndpoint Error="
       write ..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!
     }

    Como você pode ver, adicionamos o escopo da conta e o nó "accno" da array de propriedades com um valor de contexto, que pode se originar em diferentes partes do nosso aplicativo. Esse valor é transmitido dentro do token de acesso ao servidor de recursos para processamento adicional.

    Existe um cenário da vida real que usa a lógica descrita acima — o padrão FHIR para a troca de históricos eletrônicos de pacientes.

    Depuração

    O framework do OAUTH tem depuração integrada. Isso é muito útil, pois toda a comunicação entre o cliente e os servidores é criptografada. O recurso de depuração permite capturar dados de tráfego gerados pelas classes de API antes que sejam enviados pela rede. Para depurar seu código, você pode implementar uma rotina ou classe simples de acordo com o código abaixo. Você precisa implementar este código em todas as instâncias de comunicação do InterSystems IRIS! Nesse caso, é melhor fornecer um nome de arquivo que indique a função dele dentro do processo de fluxo do OAUTH. (O código de amostra abaixo é salvo como uma rotina rr.mac, mas você decide o nome.)

     // d start^rr()
    start() public {
     new $namespace
     set $namespace="%sys"
     kill ^%ISCLOG
     set ^%ISCLOG=5
     set ^%ISCLOG("Category","OAuth2")=5
     set ^%ISCLOG("Category","OAuth2Server")=5
     quit
    }
    
     // d stop^rr()
    stop() public {
     new $namespace
     set $namespace="%sys"
     set ^%ISCLOG=0
     set ^%ISCLOG("Category","OAuth2")=0
     set ^%ISCLOG("Category","OAuth2Server")=0
     quit
    
    }
    
     // display^rr()
    display() public {
     new $namespace
     set $namespace="%sys"
     do ##class(%OAuth2.Utils).DisplayLog("c:\temp\oauth2_auth_server.log")
     quit
    }

    Em seguida, antes de começar a testar, abra um terminal e invoque d start^rr() em todos os nós do InterSystems IRIS (cliente, servidor de autorização ou servidor de recursos). Depois de concluído, execute d stop^rr() e d display^rr() para preencher os arquivos de log.

    Resumo

    Nesta série de artigos, aprendemos a usar a implementação do OAuth 2.0 do InterSystems IRIS. Começando com a demonstração simples do aplicativo cliente na parte 1, seguido pela amostra complexa descrita na parte 2. Por fim, descrevemos as classes mais importantes da implementação do OAuth 2.0 e explicamos quando elas devem ser chamadas nos aplicativos dos usuários.

    Quero agradecer em especial a Marvin Tener, pela paciência infinita ao responder às minhas perguntas, às vezes idiotas, e por revisar a série.

    0
    0 149
    Artigo Danusa Calixto · Nov. 19, 2022 20m read

    Criado por Daniel Kutac, Engenheiro de vendas, InterSystems

    Aviso: se você ficar confuso com os URLs usados: a série original usou telas de uma máquina chamada dk-gs2016. As novas capturas de tela foram tiradas em uma máquina diferente. Você pode tratar o URL WIN-U9J96QBJSAG como se fosse o dk-gs2016 com segurança.

    Parte 2. Servidor de autorização, servidor OpenID Connect

    Na parte anterior desta série curta, aprendemos sobre o caso de uso simples – atuando como um cliente OAUTH[1]. Agora, é hora de levar nossa experiência a um nível completamente novo. Vamos construir um ambiente muito mais complexo, onde o InterSystems IRIS vai desempenhar todas as funções OAUTH.

    Já sabemos como fazer um cliente, então vamos nos concentrar no servidor de autorização e, ainda mais, no provedor OpenID Connect[2].

    Como na parte anterior, precisamos preparar o ambiente. Desta vez, será mais complicado, pois há mais partes móveis.

    Antes de entrarmos nos detalhes do nosso exemplo, precisamos falar algumas palavras sobre o OpenID Connect.

    Como você deve lembrar, na parte anterior, recebemos a solicitação – para ter a autorização do Google – para nos autenticarmos primeiro com o Google. A autenticação não faz parte do framework OAUTH. Na verdade, há vários frameworks de autenticação, independentes do OAUTH. Um deles é chamado OpenID. Originalmente uma iniciativa independente, ele agora aproveita a infraestrutura fornecida pelo framework OAUTH, ou seja, as estruturas de comunicação e dados. Assim, nasceu o OpenID Connect. Na verdade, muitas pessoas o chamam de OAUTH em esteroides. De fato, com o OpenID Connect, você pode não só autorizar, mas também autenticar usando interfaces bem conhecidas do framework OAUTH.

    Demonstração complexa do OpenID Connect

    Aproveitaremos grande parte do código do cliente da parte 1. Isso nos poupa muito trabalho, para que possamos nos concentrar na configuração do ambiente.

    Pré-requisitos

    Desta vez, precisamos adicionar uma infraestrutura PKI ao servidor web já existente com SSL habilitado. Precisamos de criptografia exigida pelo OpenID Connect. Se você quer autenticar alguém, precisa ter certeza absoluta de que ninguém mais pode se passar pelo agente (cliente, servidor de autenticação...) que envia os dados confidenciais pela rede. É aqui que entra a criptografia baseada em X.509.

    Observação: a partir do Cache 2017.1, não é mais necessário usar certificados X.509 para gerar JWT/JWKS (JSON Web Key Set). Devido à compatibilidade com versões anteriores e simplicidade, usamos essa opção.

    PKI

    A rigor, não precisamos usar a infraestrutura Caché PKI, mas é mais conveniente do que usar ferramentas como openssl diretamente para gerar todos os certificados.

    Não entraremos em detalhes sobre a geração de certificados aqui, pois você pode encontrá-los na documentação do InterSystems IRIS. Como resultado da geração de certificados, criaremos 3 pares de chaves públicas/privadas e certificados associados.

    Vamos chamá-los de

    ·        root_ca (root_ca.cer) para nossa autoridade de certificação emissora

    ·        auth (auth.cer e auth.key) para o servidor de autorização e OpenID

    ·        client (client.cer e client.key) para o servidor de aplicação do cliente

    Credenciais X.509

    Precisamos definir credenciais X.509 em servidores individuais para que eles possam assinar e validar JSON Web Tokens (JWT) trocados durante nossa demonstração

    Configuração do servidor de autenticação e autorização

    Sem entrar em detalhes sobre como definir credenciais X.509, apenas mostramos uma captura de tela das credenciais da instância AUTHSERVER.

    Como a imagem indica, o AUTHSERVER possui a própria chave privada e o certificado, enquanto só possui o certificado com a chave pública de CLIENT

    Configuração do servidor cliente

    Da mesma forma, as credenciais definidas na instância CLIENT

    Aqui o CLIENTE possui a chave privada e o certificado, mas somente o certificado com chave pública de AUTHSERVER.

    Configuração do servidor de recursos

    Não precisamos definir credenciais X509 na instância RESSERVER em nossa configuração de exemplo.

    Configuração do OAUTH

    Como a configuração descrita na parte 1 desta série, precisamos configurar nossos servidores para OAUTH. Vamos começar com a instância AUTHSERVER, pois é o componente central na configuração geral do OAUTH.

    AUTHSERVER

    No Portal de Gerenciamento de Sistemas, acesse System Administration (Administração do Sistema) > Security (Segurança) > OAuth 2.0 > Server Configuration (Configuração do Servidor).

    Clique no link do menu e preencha os itens do formulário:

    ·        nome do host

    ·        porta (opcional)

    ·        prefixo (opcional) – esses três campos compõem o Issuer endpoint (endpoint do emissor)

    ·        especifique as condições para retornar o token de atualização

    ·        verifique os tipos de concessão compatíveis, para nossa demonstração basta verificar todos os quatro tipos. No entanto, apenas o código de autorização é usado.

    ·        opcionalmente, confira o público-alvo necessário – isso adiciona a propriedade aud no código de autorização e solicitações implícitas

    ·        opcionalmente, confira a sessão de usuário de suporte - isso significa que o cookie httpOnly é usado pelo servidor de autorização para manter o usuário atual deste navegador conectado.  A segunda solicitação e as solicitações subsequentes do token de acesso não pedirão o nome de usuário e a senha.

    ·        especifique os intervalos de endpoint

    ·        defina os escopos compatíveis com esse servidor

    ·        aceite o padrão ou insira valores de opções de personalização – observação: altere o valor da classe de token Generate de %OAuth2.Server.Generate para %OAuth2.Server.JWT para que um JWT seja usado como token de acesso em vez de um token opaco.

    ·        forneça o nome da configuração SSL registrada para estabelecer o SSL sobre o HTTP conforme exigido pelo OAuth 2.0

    ·        Preencha as configurações do JSON Web Token (JWT) 

    Veja esta captura de tela da configuração de exemplo

    Após definir a configuração do servidor, precisamos fornecer a configuração do cliente do servidor. Na página com o formulário de configuração do servidor, clique no botão Client Configurations e pressione Create New Configuration for your CLIENT and RESSERVER instances (Criar nova configuração para as instâncias CLIENT e RESSERVER).

    Esta imagem mostra a configuração do CLIENT.

    Deixe a guia JWT Token vazia — com valores padrão. Como você pode ver, nós preenchemos os campos com dados sem sentido, diferente de um caso de aplicação real.

    Da mesma forma, a configuração do RESSERVER

    Como você pode ver, há apenas informações muito básicas necessárias para o servidor de recursos, ou seja, você precisa definir o tipo de cliente para o servidor de recursos. Com CLIENT, você precisa fornecer mais informações, o tipo de cliente (confidencial, pois nosso cliente é executado como um web app capaz de manter o cliente em segredo no servidor, e não enviar para o agente cliente).

    CLIENT

    No SMP, acesse System Administration (Administração do Sistema) > Security (Segurança) > OAuth 2.0 > Client Configurations (Configurações do cliente).

    Clique no botão Create Server Configuration (Criar configuração de servidor), preencha o formulário e salve.

    Confira se o endpoint do emissor corresponde ao valor que definimos anteriormente na instância AUTHSERVER! Você também precisa modificar os endpoints do servidor de autorização de acordo com a configuração do seu servidor web. No nosso caso, apenas incorporamos 'authserver' em cada campo de entrada.

    Agora, clique no link Client Configurations (Configurações do cliente) ao lado do Issuer Endpoint (Endpoint emissor) recém-criado e clique no botão Create Client Configuration (Criar configuração de cliente).

    Ótimo! Agora, temos CLIENT e AUTHSERVER configurados. Isso pode ser suficiente para muitos casos de uso, pois o servidor de recursos pode ser apenas um namespace de AUTHSERVER, já protegido. Porém, vamos considerar que queremos cobrir um caso de uso em que um médico externo está tentando recuperar dados do nosso sistema clínico interno. Portanto, para permitir que esse médico recupere os dados, queremos armazenar as informações da conta dele DENTRO do nosso servidor de recursos para auditorias e fins forenses. Nesse caso, precisamos continuar e definir as configurações em RESSERVER.

    RESSERVER

    No SMP, acesse System Administration (Administração do Sistema) > Security (Segurança) > OAuth 2.0 > Client Configurations (Configurações do cliente).

    Clique no botão Create Server Configuration (Criar configuração de servidor), preencha o formulário e salve.

    Usamos a função de descoberta, um novo recurso implementado no Cache 2017.1

    Como você pode ver, essa configuração está usando os mesmos dados que a configuração correspondente na instância CLIENT.

    Agora, clique no link Client Configurations (Configurações do cliente) ao lado do Issuer Endpoint (Endpoint emissor) recém-criado e clique no botão Create Client Configuration (Criar configuração de cliente).

    A criação do WT a partir das credenciais X.509 não é recomendada, mas nós as usamos para a compatibilidade.

    Isso! Foi um processo tedioso, mas necessário. Agora, podemos avançar e começar a programar!

    Aplicativo cliente

    Para manter as coisas o mais simples possível, reciclaremos grande parte do código do nosso exemplo do Google que descrevemos na parte 1.

    O aplicativo cliente tem apenas duas páginas de CSP, sendo executado no aplicativo /csp/myclient, sem segurança aplicada – ele é apenas executado como usuário não autenticado.

    Página 1

    Class Web.OAUTH2.Cache1N Extends %CSP.Page
    {
    
    Parameter OAUTH2CLIENTREDIRECTURI = "https://dk-gs2016/client/csp/myclient/Web.OAUTH2.Cache2N.cls";
    
    Parameter OAUTH2APPNAME = "demo client";
    
    ClassMethod OnPage() As %Status
    {
      &html<<html>
    
    <body>
      <h1>Authenticating and Authorizing against Cache&acute; OAuth2 provider</h1>
      <p>This page demo shows how to call Cache&acute; API functions using OAuth2 authorization.
      <p>We are going to call Cache&acute; authentication and authorization server to grant our application access to data stored at another
      Cache&acute; server.
     >
    
      // Get the url for authorization endpoint with appropriate redirect and scopes.
      // The returned url is used in the button below.
    
      // DK: use 'dankut' account to authenticate!
      set scope="openid profile scope1 scope2"
      set url=##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint(
        ..#OAUTH2APPNAME,
        scope,
        ..#OAUTH2CLIENTREDIRECTURI,
        .properties,
        .isAuthorized,
        .sc)
      if $$$ISERR(sc) {
        write "GetAuthorizationCodeEndpoint Error="
        write ..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!
      } 
    
      &html<
      <div class="portalLogoBox"><a class="portalLogo" href="#(url)#">Authorize for <b>ISC</b></a></div>
      </body></html>>
      Quit $$$OK
    }
    
    ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ]
    {
      #dim %response as %CSP.Response
      set scope="openid profile scope1 scope2"
      if ##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,scope,.accessToken,.idtoken,.responseProperties,.error) {
        set %response.ServerSideRedirect="Web.OAUTH2.Cache2N.cls"
      }
      quit 1
    }
    
    }
    

    Página 2

    Class Web.OAUTH2.Cache2N Extends %CSP.Page
    {
    
    Parameter OAUTH2APPNAME = "demo client";
    
    Parameter OAUTH2ROOT = "https://dk-gs2016/resserver";
    
    Parameter SSLCONFIG = "SSL4CLIENT";
    
    ClassMethod OnPage() As %Status
    {
        &html<<html>
    
    
    
    
    <body>>
        
        // Check if we have an access token from oauth2 server
        set isAuthorized=##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,"scope1 scope2",.accessToken,.idtoken,.responseProperties,.error)
        
        // Continue with further checks if an access token exists.
        // Below are all possible tests and may not be needed in all cases.
        // The JSON object which is returned for each test is just displayed.
        if isAuthorized {
            write "<h3>Authorized!</h3>",!
            
            
            // Validate and get the details from the access token, if it is a JWT.
            set valid=##class(%SYS.OAuth2.Validation).ValidateJWT(..#OAUTH2APPNAME,accessToken,"scope1 scope2",,.jsonObject,.securityParameters,.sc)
            if $$$ISOK(sc) {
                if valid {
                    write "Valid JWT"_"<br>",!    
                } else {
                    write "Invalid JWT"_"<br>",!    
                }
                write "Access token="
                do jsonObject.%ToJSON()
                write "<br>",!
            } else {
                write "JWT Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!    
            }
            write "<br>",!
    
            // Call the introspection endpoint and display result -- see RFC 7662.
            set sc=##class(%SYS.OAuth2.AccessToken).GetIntrospection(..#OAUTH2APPNAME,accessToken,.jsonObject)
            if $$$ISOK(sc) {
                write "Introspection="
                do jsonObject.%ToJSON()
                write "<br>",!
            } else {
                write "Introspection Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!    
            }
            write "<br>",!
            
            if idtoken'="" {
                // Validate and display the IDToken -- see OpenID Connect Core specification.
                set valid=##class(%SYS.OAuth2.Validation).ValidateIDToken(
                    ..#OAUTH2APPNAME,
                    idtoken,
                    accessToken,,,
                    .jsonObject,
                    .securityParameters,
                    .sc)
                if $$$ISOK(sc) {
                    if valid {
                        write "Valid IDToken"_"<br>",!    
                    } else {
                        write "Invalid IDToken"_"<br>",!    
                    }
                    write "IDToken="
                    do jsonObject.%ToJSON()
                    write "<br>",!
                } else {
                    write "IDToken Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!    
                }
            } else {
                write "No IDToken returned"_"<br>",!
            }
            write "<br>",!
        
            // not needed for the application logic, but provides information about user that we can pass to Delegated authentication
        
            // Call the userinfo endpoint and display the result -- see OpenID Connect Core specification.
            set sc=##class(%SYS.OAuth2.AccessToken).GetUserinfo(
                ..#OAUTH2APPNAME,
                accessToken,,
                .jsonObject)
            if $$$ISOK(sc) {
                write "Userinfo="
                do jsonObject.%ToJSON()
                write "<br>",!
            } else {
                write "Userinfo Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!    
            }
            write "<p>",!
    
            /***************************************************
            *                                                  *
            *   Call the resource server and display result.   *
            *                                                  *
            ***************************************************/
                    
            // option 1 - resource server - by definition - trusts data coming from authorization server,
            //     so it serves data to whoever is asking
            //  as long as access token passed to resource server is valid
            
            // option 2 - alternatively, you can use delegated authentication (OpenID Connect) 
            //  and call into another CSP application (with delegated authentication protection)
            //  - that's what we do here in this demo
            
            
            write "<4>Call resource server (delegated auth)","</h4>",!
            set httpRequest=##class(%Net.HttpRequest).%New()
            // AddAccessToken adds the current access token to the request.
            set sc=##class(%SYS.OAuth2.AccessToken).AddAccessToken(
                httpRequest,,
                ..#SSLCONFIG,
                ..#OAUTH2APPNAME)
            if $$$ISOK(sc) {
                set sc=httpRequest.Get(..#OAUTH2ROOT_"/csp/portfolio/oauth2test.demoResource.cls")
            }
            if $$$ISOK(sc) {
                set body=httpRequest.HttpResponse.Data
                if $isobject(body) {
                    do body.Rewind()
                    set body=body.Read()
                }
                write body,"<br>",!
            }
            if $$$ISERR(sc) {
                write "Resource Server Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!    
            }
            write "<br>",!
        
            write "<h4>Call resource server - no auth, just token validity check","</h4>",!
            set httpRequest=##class(%Net.HttpRequest).%New()
            // AddAccessToken adds the current access token to the request.
            set sc=##class(%SYS.OAuth2.AccessToken).AddAccessToken(
                httpRequest,,
                ..#SSLCONFIG,
                ..#OAUTH2APPNAME)
            if $$$ISOK(sc) {
                set sc=httpRequest.Get(..#OAUTH2ROOT_"/csp/portfolio2/oauth2test.demoResource.cls")
            }
            if $$$ISOK(sc) {
                set body=httpRequest.HttpResponse.Data
                if $isobject(body) {
                    do body.Rewind()
                    set body=body.Read()
                }
                write body,"<br>",!
            }
            if $$$ISERR(sc) {
                write "Resource Server Error="_..EscapeHTML($system.Status.GetErrorText(sc))_"<br>",!    
            }
            write "<br>",!
        } else {
            write "Not Authorized!<p>",!
            write "<a href='Web.OAUTH2.Cache1N.cls'>Authorize me</a>"
        }    
        &html<</body></html>>
        Quit $$$OK
    }
    
    }
    

    As seguintes capturas de tela retratam o processamento:

    Página de login do servidor de autenticação do OpenID Connect/autorização na instância AUTHSERVER

    Página de consentimento do usuário em AUTHSERVER

    E, por fim, a página resultante

    Como você pode ver, lendo o código, realmente quase não há diferença em relação ao código do cliente que mostramos na parte 1. Há algo novo na página 2. São algumas informações de depuração e a verificação da validade do JWT. Depois de validar o JWT retornado, podemos realizar a introspeção dos dados do AUTHSERVER sobre a identidade do usuário. Simplesmente apresentamos essas informações nos resultados da página, mas podemos fazer mais com elas. Como no caso de uso de um médico externo mencionado acima, podemos usar as informações de identidade e transmiti-las ao servidor de recursos para fins de autenticação, se necessário. Ou apenas passar essa informação como um parâmetro para a chamada da API ao servidor de recursos.

    Os próximos parágrafos descrevem como usamos as informações de identidade do usuário em mais detalhes.

    Aplicativo de recurso

    O servidor de recursos pode ser o mesmo servidor que o servidor de autorização/autenticação e, muitas vezes, esse é o caso. No entanto, na nossa demonstração, criamos para os dois servidores instâncias do InterSystems IRIS separadas.

    Então, temos dois casos possíveis, como trabalhar com o contexto de segurança no servidor de recursos.

    Alternativa 1 — sem autenticação

    Esse é o caso simples. O servidor de autorização/autenticação são apenas a mesma instância do Caché. Nesse caso, podemos simplesmente transmitir o token de acesso a um aplicativo CSP, que é criado especialmente para um único propósito — enviar dados a aplicativos clientes que usam o OAUTH para autorizar a solicitação de dados.

    A configuração do aplicativo CSP de recurso (chamamos de /csp/portfolio2) pode parecer com a captura de tela abaixo.

    Colocamos o mínimo de segurança na definição do aplicativo, permitindo que apenas a página CSP específica seja executada.

    Como opção, o servidor de recursos pode fornecer uma API REST em vez de páginas da Web clássicas. Em situações reais, o refinamento do contexto de segurança depende do usuário.

    Um exemplo de código-fonte:

    Class oauth2test.demoResource Extends %CSP.Page
    {
    
    ClassMethod OnPage() As %Status
    {
        set accessToken=##class(%SYS.OAuth2.AccessToken).GetAccessTokenFromRequest(.sc)
        if $$$ISOK(sc) {
            set sc=##class(%SYS.OAuth2.AccessToken).GetIntrospection("RESSERVER resource",accessToken,.jsonObject)
            if $$$ISOK(sc) {        
                // optionally validate against fields in jsonObject
    
                w "<p><h3>Hello from Cach&eacute; server: <i>/csp/portfolio2</i> application!</h3>"
                w "<p>running code as <b>$username = "_$username_"</b> with following <b>$roles = "_$roles_"</b> at node <b>"_$p($zu(86),"*",2)_"</b>."
            }
        } else {
            w "<h3>NOT AUTHORIZED!</h3>"    
            w "<pre>"
            w
            i $d(%objlasterror) d $system.OBJ.DisplayError()
            w "</pre>"
        }
        Quit $$$OK
    }
    
    }
    

    Alternativa 2 — autenticação delegada

    Esse é outro caso extrema, queremos usar a identidade do usuário no servidor de recursos o máximo possível, como se o usuário estivesse trabalhando com o mesmo contexto de segurança que os usuários internos do servidor de recursos.

    Uma das opções possíveis é usar a autenticação delegada.

    Para essa definição funcionar, precisamos concluir mais algumas etapas para configurar o servidor de recursos.

    ·        Ativar a autenticação delegada

    ·        Fornecer a rotina ZAUTHENTICATE

    ·        Configurar o Web application (no nosso caso, chamamos em /csp/portfolio)

    A implementação da rotina ZAUTHENTICATE é bastante simples e direta, já que confiamos no AUTHSERVER que forneceu a identidade do usuário e o escopo (perfil de segurança) dele, então basta aceitar o nome de usuário e transmitir com o escopo ao banco de dados de usuários do servidor de recursos (com a tradução necessária entre o escopo do OAUTH e as funções do InterSystems IRIS). É isso. O resto é realizado perfeitamente pelo InterSystems IRIS.

    Veja o exemplo de uma rotina ZAUTHENTICATE

    #include %occErrors
    #include %occInclude
    
    ZAUTHENTICATE(ServiceName, Namespace, Username, Password, Credentials, Properties) PUBLIC
    {
        set tRes=$SYSTEM.Status.OK()
        try {        
            set Properties("FullName")="OAuth account "_Username
            //set Properties("Roles")=Credentials("scope")
            set Properties("Username")=Username
            //set Properties("Password")=Password
            // temporary hack as currently we can't pass Credentials array from GetCredentials() method
            set Properties("Password")="xxx"    // we don't really care about oauth2 account password
            set Properties("Roles")=Password
        } catch (ex) {
            set tRes=$SYSTEM.Status.Error($$$AccessDenied)
        }
        quit tRes
    }
    
    GetCredentials(ServiceName,Namespace,Username,Password,Credentials) Public 
    {
        s ts=$zts
        set tRes=$SYSTEM.Status.Error($$$AccessDenied)        
    
         try {
             If ServiceName="%Service_CSP" {
                set accessToken=##class(%SYS.OAuth2.AccessToken).GetAccessTokenFromRequest(.sc)
                if $$$ISOK(sc) {
                    set sc=##class(%SYS.OAuth2.AccessToken).GetIntrospection("RESSERVER resource",accessToken,.jsonObject)
                    if $$$ISOK(sc) {
                        // todo: watch out for potential collision between standard account and delegated (openid) one!
                        set Username=jsonObject.username
                        set Credentials("scope")=$p(jsonObject.scope,"openid profile ",2)
                        set Credentials("namespace")=Namespace
                        // temporary hack
                        //set Password="xxx"
                        set Password=$tr(Credentials("scope")," ",",")
                        set tRes=$SYSTEM.Status.OK()
                    } else {
                        set tRes=$SYSTEM.Status.Error($$$GetCredentialsFailed) 
                    }
                }    
            } else {
                set tRes=$SYSTEM.Status.Error($$$AccessDenied)        
            }
         } catch (ex) {
             set tRes=$SYSTEM.Status.Error($$$GetCredentialsFailed)
        }
        Quit tRes
    }
    

    A própria página CSP pode ser bastante simples:

    Class oauth2test.demoResource Extends %CSP.Page
    {
    
    ClassMethod OnPage() As %Status
    {
        // access token authentication is performed by means of Delegated authentication!
        // no need to do it, again, here
    
        // This is a dummy resource server which just gets the access token from the request and
        // uses the introspection endpoint to ensure that the access token is valid.
        // Normally the response would not be security related, but would contain some interesting
        // data based on the request parameters.
        w "<p><h3>Hello from Cach&eacute; server: <i>/csp/portfolio</i> application!</h3>"
        w "<p>running code as <b>$username = "_$username_"</b> with following <b>$roles = "_$roles_"</b> at node <b>"_$p($zu(86),"*",2)_"</b>."
        Quit $$$OK
    }
    
    }
    

    Por fim, a configuração do Web application para /csp/portfolio

    Se você estiver muito paranoico, pode definir Classes permitidas como fizemos na primeira variante. Ou, novamente, use a API REST. No entanto, isso está muito além do escopo do nosso tema.

    Na próxima vez, vamos explicar classes individuais, apresentadas pelo framework OAUTH do InterSystems IRIS. Descreveremos as APIs e quando/onde chamá-las.

     

    [1] Quando mencionamos o OAUTH, queremos dizer o OAuth 2.0 conforme especificado no RFC 6749 - https://tools.ietf.org/html/rfc6749. Usamos a abreviação OAUTH apenas por simplicidade.

    [2] O OpenID Connect é mantido pela OpenID Foundation – http://openid.net/connect

    0
    0 218
    Artigo Daniel Kutac · Nov. 19, 2022 14m read

    Este artigo e os próximos dois artigos da série são um guia do usuário para desenvolvedores ou administradores de sistema que precisam usar o framework OAuth 2.0 (chamado de OAUTH para simplificar) em suas aplicações baseadas no produto InterSystems.

    Criado por Daniel Kutac, Engenheiro de vendas sênior, InterSystems

    Histórico de correções e alterações após a publicação

    • 3 de agosto de 2016 – Correção da captura de tela da configuração do Google Client; atualização da captura de tela das APIs do Google para refletir a nova versão das páginas.
    • 28 de agosto de 2016 – Alterações do código JSON devido às mudanças no suporte ao JSON do Caché 2016.2.
    • 3 de maio de 2017 – Atualizações do texto e imagens para refletir a nova interface gráfica e os novos recursos lançados no Caché 2017.1. 
    • 19 de fevereiro de 2018 – Alteração de Caché para InterSystems IRIS para refletir os desenvolvimentos mais recentes. Porém, é importante salientar que, apesar da alteração do nome do produto, o artigo aborda todos os produtos da InterSystems: InterSystems IRIS Data Platform, Ensemble e Caché.
    • 17 de agosto de 2020 – Tudo muda, especialmente o software. Consulte o URL do OAuth2 do Google atualizado na resposta do Micholai Mitchko.

    Parte 1. Cliente

    Introdução

    Esta é a primeira parte de uma série de três artigos sobre a implementação do Open Authorization Framework na InterSystems.

    Nesta primeira parte, apresentamos uma breve introdução do tópico e mostramos um cenário simples em que a aplicação InterSystems IRIS atua como cliente de um servidor de autorização, solicitando alguns recursos protegidos.

    A segunda parte descreverá um cenário mais complexo, em que a InterSystems IRIS atua como servidor de autorização e também como servidor de autenticação via OpenID Connect.

    A última parte da série descreverá partes individuais das classes do framework OAUTH conforme implementadas pela InterSystems IRIS.

    Sobre o Open Authorization Framework[1]

    Muitos de vocês já ouviram falar do Open Authorization Framework e para que ele pode ser usado. Vamos resumir para quem ainda não tiver ouvido falar dele.

    O Open Authorization Framework, OAUTH, atualmente na versão 2.0, é um protocolo que permite principalmente que aplicações web troquem informações de forma segura estabelecendo uma confiança indireta entre um cliente (aplicação que solicita dados) e o proprietário dos recursos (aplicação que detém os dados solicitados). A confiança é fornecida por uma entidade que tanto o cliente quanto o servidor de recursos reconhecem e na qual confiam. Essa entidade é chamada de servidor de autorização.

    Veja um caso de uso simples:

    Vamos supor que Jenny (na terminologia do OAUTH, é o proprietário dos recursos) esteja trabalhando em um projeto na empresa JennyCorp. Ela cria um plano de projeto para um possível negócio maior e convida seu parceiro comercial John (usuário cliente) da empresa JohnInc para revisar o documento. Mas ela não está contente de dar ao John acesso à VPN de sua empresa, então ela coloca o documento no Google Drive (o servidor de recursos) ou outra ferramenta de armazenamento em nuvem similar. Ao fazer isso, ela estabeleceu uma confiança entre ela e o Google (o servidor de autorização). Ela compartilha o documento com John (John já usa o serviço Google Drive, e Jenny sabe qual é o e-mail dele).

    Quando John deseja ler o documento, ele faz a autenticação em sua conta do Google e, em seu dispositivo móvel (tablet, notebook, etc.), abre um editor de documentos (o servidor cliente) e carrega o arquivo do projeto da Jenny.

    Embora pareça bem simples, há muita comunicação entre as duas pessoas e o Google. Todas as comunicações seguem a especificação do OAuth 2.0, então o cliente de John (o leitor de documentos) precisa primeiro fazer a autenticação no Google (essa etapa não é coberta pelo OAUTH) e, após John consentir autorização no formulário fornecido pelo Google, o Google autoriza que o leitor de documentos acesse o documento emitindo um token de acesso. O leitor de documentos usa o token de acesso para emitir uma solicitação ao serviço Google Drive para obter o arquivo de Jenny.

    O diagrama abaixo mostra a comunicação entre todas as partes

    Nota: embora todas as comunicações do OAUTH 2.0 sejam feitas por solicitações HTTP, os servidores não precisam ser aplicações web.

    Vamos ilustrar esse cenário simples com a InterSystems IRIS

    Demonstração simples do Google Drive

    Nesta demonstração, vamos criar uma aplicação de pequeno porte baseada em Cloud Solution Provider (CSP) que solicita recursos (lista de arquivos) armazenados no serviço Google Drive com nossa própria conta (e também uma lista de nossos calendários, como bônus).

    Pré-requisitos

    Antes de começarmos a programar a aplicação, precisamos preparar o ambiente. Precisaremos de um servidor web com SSL ativado e um perfil do Google.

    Configuração do servidor web

    Conforme informado acima, precisamos estabelecer comunicação com o servidor de autorização com SSL, pois isso é exigido pelo OAuth 2.0 por padrão. Queremos manter nossos dados seguros, certo?

    Está fora do escopo deste artigo descrever como configurar um servidor web com suporte ao SSL, então consulte os manuais de usuário do servidor web de sua preferência. Usaremos o servidor IIS da Microsoft neste exemplo específico.

    Configuração do Google

    Para nos registrarmos no Google, precisamos usar o Google API Manager: https://console.developers.google.com/apis/library?project=globalsummit2016demo

    Para o propósito da demonstração, criamos uma conta GlobalSummit2016Demo. É preciso confirmar se a API do Drive está ativada

    Agora, está na hora de definir as credenciais

    Observe o seguinte:

    _Authorized JavaScript (JavaScript autorizado) –  permitimos somente scripts originados localmente em relação à página chamadora

    _Authorized redirect URIs (URIs de redirecionamento autorizados) –  teoricamente, podemos redirecionar nossa aplicação cliente para qualquer site, mas, ao usar a implementação do OAUTH da InterSystems IRIS, precisamos redirecioná-la para https://localhost/csp/sys/oauth2/OAuth2.Response.cls. É possível definir vários URIs de redirecionamento autorizados, conforme mostrado na captura de tela, mas, para esta demonstração, só precisamos da segunda entrada.

    Por último, precisamos configurar a InterSystems IRIS como cliente do servidor de autorização do Google

    Configuração do Caché

    A configuração do cliente OAUTH2 da InterSystems IRIS é um processo de duas etapas. Primeiro, precisamos criar uma configuração de servidor.

    No SMP, acesse System Administration (Administração do Sistema) > Security (Segurança) > OAuth 2.0 > Client Configurations (Configurações do cliente).

    Clique no botão Create Server Configuration (Criar configuração de servidor), preencha o formulário e salve.

    Todas as informações inseridas no formulário estão disponíveis no site do console de desenvolvedores do Google. A InterSystems IRIS tem suporte à descoberta automática do Open ID. Entretanto, não estamos usando esse recurso. Inserimos todas as informações manualmente 

    Agora, clique no link Client Configurations (Configurações do cliente) ao lado do Issuer Endpoint (Endpoint emissor) recém-criado
    e clique no botão Create Client Configuration (Criar configuração de cliente).

    Deixe as abas Client Information (Informações do cliente) e JWT Settings (Configurações do JWT) em branco (com os valores padrão) e preencha a aba Client credentials (Credenciais do cliente).

    Nota: estamos criando um Confidential Client (Cliente confidencial – é mais seguro que o público e significa que o segredo do cliente nunca deixa a aplicação do servidor cliente – nunca é transmitido ao navegador)

    Além disso, confirme se Use SSL/TLS (Usar SSL/TLS) está marcado e forneça o nome do host (localhost, já que estamos redirecionando localmente para a aplicação cliente) e, posteriormente, a porta e o prefixo (útil quando há várias instâncias da InterSystems IRIS na mesma máquina). Com base nas informações preenchidas, o URL de redirecionamento do cliente é computado e exibido na linha acima.

    Na captura de tela acima, fornecemos uma configuração SSL chamada GOOGLE. O nome é usado somente para ajudar a determinar qual configuração SSL dentre várias é usada por esse canal de comunicação específico. O Caché está usando configurações SSL/TLS para armazenar todas as informações necessárias para receber/enviar tráfego seguro ao servidor (neste caso, os URIs OAuth 2.0 do Google).

    Consulte mais detalhes na documentação.

    Preencha os valores Client ID (ID do cliente) e Client Secret (Segredo do cliente) obtidos pelo formulário de definição das credenciais do Google (ao fazer a configuração manual).

    Agora, concluímos todas as etapas de configuração e podemos prosseguir para a programação de uma aplicação CSP.

    Aplicação cliente

    A aplicação cliente é uma aplicação CSP web simples. Ela é composta por um código fonte no servidor, definido e executado pelo servidor web, e uma interface do usuário, exibida ao usuário por um navegador. O exemplo de código fornecido espera que a aplicação cliente seja executada no namespace GOOGLE. Modifique o caminho /csp/google/  para o seu namespace.

    Servidor cliente

    O servidor cliente é uma aplicação simples de duas páginas. Dentro da aplicação, nós vamos:

    ·        Montar o URL de redirecionamento para o servidor de autorização do Google

    ·        Fazer solicitações à API do Google Drive e à API do Google Agenda e exibir o resultado

    Página 1

    Esta é uma página da aplicação, na qual decidimos fazer uma chamada aos recursos do Google.

    Veja abaixo um código minimalista, mas completamente funcional, que representa a página.

    Class Web.OAUTH2.Google1N Extends %CSP.Page{Parameter OAUTH2CLIENTREDIRECTURI = "https://localhost/csp/google/Web.OAUTH2.Google2N.cls";Parameter OAUTH2APPNAME = "Google";ClassMethod OnPage() As %Status{&html<<html><head></head><body style="text-align: center;"><!-- insert the page content here --><h1>Google OAuth2 API</h1><p>This page demo shows how to call Google API functions using OAuth2 authorization.<p>We are going to retrieve information about user and his/her Google Drive files as well as calendar entries.>// we need to supply openid scope to authenticate to Googleset scope="openid https://www.googleapis.com/auth/userinfo.email "_"https://www.googleapis.com/auth/userinfo.profile "_"https://www.googleapis.com/auth/drive.metadata.readonly "_"https://www.googleapis.com/auth/calendar.readonly"set properties("approval_prompt")="force"set properties("include_granted_scopes")="true"set url=##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint(..#OAUTH2APPNAME,scope,..#OAUTH2CLIENTREDIRECTURI,.properties,.isAuthorized,.sc) w !,"<p><a href='"_url_"'><img border='0' alt='Google Sign In' src='images/google-signin-button.png' ></a>" &html<</body></html>>Quit $$$OK}ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ]{#dim %response as %CSP.Responseset scope="openid https://www.googleapis.com/auth/userinfo.email "_"https://www.googleapis.com/auth/userinfo.profile "_"https://www.googleapis.com/auth/drive.metadata.readonly "_"https://www.googleapis.com/auth/calendar.readonly"if ##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,scope,.accessToken,.idtoken,.responseProperties,.error) {set %response.ServerSideRedirect="Web.OAUTH2.Google2N.cls"}quit 1}}

    Veja abaixo uma breve explicação do código:

    1.      Método OnPreHTTP: primeiro, verificamos se, por acaso, já obtivemos um token de acesso válido como resultado de uma autorização do Google. Isso pode acontecer, por exemplo, quando simplesmente atualizamos a página. Caso não tenhamos, precisamos fazer a autorização. Se já tivermos o token, apenas redirecionamos para a página que mostra os resultados

    2.       Método OnPage: só chegamos a este método se não tivermos um token de acesso válido disponível. Então, precisamos iniciar a comunicação: fazer a autenticação e autorização no Google para que ele nos conceda o token de acesso.

    3.       Definimos uma string de escopo e uma array de propriedades que modificam o comportamento da janela de autenticação do Google (precisamos fazer a autenticação no Google antes que ele possa nos autorizar com base em nossa identidade).

    4.       Por último, recebemos o URL de uma página de login do Google e a mostramos ao usuário, seguida pela página de consentimento.

    Mais uma nota:

    Especificamos a verdadeira página de redirecionamento em https://www.localhost/csp/google/Web.OAUTH2.Google2N.cls no parâmetro OAUTH2CLIENTREDIRECTURI. Entretanto, usamos a página de sistema do framework OAUTH da InterSystems IRIS na definição das credenciais do Google! O redirecionamento é tratado internamente por nossa classe manipuladora OAUTH.

    Página 2

    Esta página mostra os resultados da autorização do Google e, em caso de êxito, fazemos chamadas à API do Google para obter os dados. Novamente, o código abaixo é minimalista, mas completamente funcional. Deixamos a exibição dos dados recebidos de uma maneira mais estruturada para a imaginação dos leitores.

    Include %occIncludeClass Web.OAUTH2.Google2N Extends %CSP.Page{Parameter OAUTH2APPNAME = "Google";Parameter OAUTH2ROOT = "https://www.googleapis.com";ClassMethod OnPage() As %Status{&html<<html><head></head><body>>// Check if we have an access tokenset scope="openid https://www.googleapis.com/auth/userinfo.email "_"https://www.googleapis.com/auth/userinfo.profile "_"https://www.googleapis.com/auth/drive.metadata.readonly "_"https://www.googleapis.com/auth/calendar.readonly"set isAuthorized=##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,scope,.accessToken,.idtoken,.responseProperties,.error)if isAuthorized { // Google has no introspection endpoint - nothing to call - the introspection endpoint and display result -- see RFC 7662.w "<h3>Data from <span style='color:red;'>GetUserInfo API</span></h3>"// userinfo has special API, but could be also retrieved by just calling Get() method with appropriate urltry {set tHttpRequest=##class(%Net.HttpRequest).%New()$$$THROWONERROR(sc,##class(%SYS.OAuth2.AccessToken).AddAccessToken(tHttpRequest,"query","GOOGLE",..#OAUTH2APPNAME))$$$THROWONERROR(sc,##class(%SYS.OAuth2.AccessToken).GetUserinfo(..#OAUTH2APPNAME,accessToken,,.jsonObject))w jsonObject.%ToJSON()} catch (e) {w "<h3><span style='color: red;'>ERROR: ",$zcvt(e.DisplayString(),"O","HTML")_"</span></h3>"}/*********************************************Retrieve info from other APIs*********************************************/w "<hr>"do ..RetrieveAPIInfo("/drive/v3/files")do ..RetrieveAPIInfo("/calendar/v3/users/me/calendarList")} else {w "<h1>Not authorized!</h1>"}&html<</body></html>>Quit $$$OK}ClassMethod RetrieveAPIInfo(api As %String){w "<h3>Data from <span style='color:red;'>"_api_"</span></h3><p>"try {set tHttpRequest=##class(%Net.HttpRequest).%New()$$$THROWONERROR(sc,##class(%SYS.OAuth2.AccessToken).AddAccessToken(tHttpRequest,"query","GOOGLE",..#OAUTH2APPNAME))$$$THROWONERROR(sc,tHttpRequest.Get(..#OAUTH2ROOT_api))set tHttpResponse=tHttpRequest.HttpResponses tJSONString=tHttpResponse.Data.Read()if $e(tJSONString)'="{" {// not a JSONd tHttpResponse.OutputToDevice()} else {w tJSONStringw "<hr/>"/*// new JSON API&html<<table border=1 style='border-collapse: collapse'>>s tJSONObject={}.%FromJSON(tJSONString)set iterator=tJSONObject.%GetIterator()while iterator.%GetNext(.key,.value) {if $isobject(value) {set iterator1=value.%GetIterator()w "<tr><td>",key,"</td><td><table border=1 style='border-collapse: collapse'>"while iterator1.%GetNext(.key1,.value1) {if $isobject(value1) {set iterator2=value1.%GetIterator()w "<tr><td>",key1,"</td><td><table border=0 style='border-collapse: collapse'>"while iterator2.%GetNext(.key2,.value2) {write !, "<tr><td>",key2, "</td><td>",value2,"</td></tr>"}// this way we can go on and on into the embedded objects/arraysw "</table></td></tr>"} else {write !, "<tr><td>",key1, "</td><td>",value1,"</td></tr>"}}w "</table></td></tr>"} else {write !, "<tr><td>",key, "</td><td>",value,"</td></tr>"}}&html<</table><hr/>>*/}} catch (e) {w "<h3><span style='color: red;'>ERROR: ",$zcvt(e.DisplayString(),"O","HTML")_"</span></h3>"}}}

     

    Vamos dar uma olhada no código:

    1.       Antes de tudo, precisamos verificar se temos um token de acesso válido (para verificarmos se fomos autorizados)

    2.       Caso afirmativo, podemos enviar solicitações às APIs oferecidas pelo Google usando o token de acesso emitido

    3.       Para isso, usamos a classe padrão %Net.HttpRequest, mas adicionamos o token de acesso ao método GET ou POST de acordo com a especificação da API chamada

    4.       Como é possível ver, o framework OAUTH implementou o método GetUserInfo() para sua comodidade, mas você pode obter as informações do usuário diretamente usando a especificação da API do Google da mesma maneira como feito no método auxiliar RetrieveAPIInfo()

    5.       Como é comum no mundo do OAUTH trocar dados no formato JSON, apenas lemos os dados recebidos e os colocamos no navegador. Cabe ao desenvolvedor da aplicação analisar e formatar os dados recebidos para apresentá-los ao usuário de alguma forma que faça sentido. Mas isso está além do escopo desta demonstração. (Embora tenhamos colocado um código comentado que mostra como a análise pode ser feita.)

     Veja abaixo uma captura de tela da saída exibindo os dados JSON não tratados.

    Prossiga para a parte 2, que descreve como a InterSystems IRIS atua como servidor de autorização e provedor do OpenID Connect.

    0
    0 240
    Artigo Kevin Koloska · Nov. 15, 2022 11m read

    Construção de um repositório FHIR + o servidor de autorização/recurso OAuth2 no IRIS for Health - Parte 2 IRIS para #FHIR #OAuth2 #InterSystems de Saúde Olá, caros desenvolvedores! Neste artigo, vamos focar-nos na OAuth2, um protocolo que é cada vez mais utilizado em combinação com o FHIR para realizar permissões. Nesta parte 1, iniciaremos o contentor Docker para IRIS para a Saúde e Apache, configuraremos a função do servidor de autorização OAuth2 na IRIS for Health, acedemos-lhe a partir da ferramenta de desenvolvimento do Postman REST e obteremos um token de acesso. Além disso, na segunda parte e além, adicionaremos a funcionalidade de repositório FHIR à IRIS for Health, adicionamos a configuração do servidor de recursos OAuth2 e explicaremos como executar consultas de FHIR com fichas de acesso de dentro do Carteiro.

    Vários artigos excelentes já foram publicados dentro da comunidade de desenvolvedores para explicar a funcionalidade OAuth2 dos produtos InterSystems; No entanto, gostaria de explicar mais uma vez como criar a versão mais recente. Implementação do Quadro de Autorização Aberta IRIS InterSystems (Oauth 2.0) - Parte 1 Neste artigo, utilizaremos a versão mais recente da InterSystems IRIS for Health 2020.3 Preview Edition. Se pretender criar um ambiente baseado neste artigo, não se esqueça de utilizar esta ou uma versão posterior do kit. Algumas funcionalidades não estão incluídas em produtos antes desta versão. Preparativos preliminares O primeiro passo é fazer os preparativos preliminares. Há muitas coisas para se preparar para construir um ambiente seguro. IRIS for Health 2020.3 Preview Edition só está disponível como uma versão de recipiente Docker. (InterSystems Docker Hub/IRIS for Health)Para executar a configuração OAuth2, também terá de executar o servidor web e a configuração SSL. Neste artigo, utilizaremos Apache.Quando configurar o SSL em Apache, o certificado de configuração SSL deve corresponder ao nome de anfitrião do servidor. Por favor, tenha isso em conta.

    Obtenha ficheiros de amostra do repositório Do GitHub interssistema-jp O estivador-compose.yml/Dockerfile e outros ficheiros de amostras utilizados nesta configuração estão disponíveis no repositório GitHub para a comunidade de desenvolvedores intersystems.Em primeiro lugar, desaperte este ficheiro no seu ambiente utilizando o seguinte comando. (Também pode fazê-lo a partir do anexo a este artigo.) Este docker-compose.yml/Dockerfile e outros ficheiros são criados referindo-se à aplicação iris-webgateway-exemplo publicada no OpenExchange. https://github.com/Intersystems-jp/IRIS4H-OAuth2-handson.git de clone de Git Alterar a configuração de acordo com o kit utilizado Neste ficheiro docker-compose.yml, estão configurados dois contentores: o contentor IRIS for Health e o contentor Apache (httpd) serão criados pelo comando de construção de estivadores. O ficheiro docker-compose.yml, disponível no GitHub, refere IRIS for Health Community Edition Preview Edition (2020.3.200.0). A Edição Comunitária pode ser utilizada para a avaliação dos produtos InterSystems.

    íris: Imagem: loja/intersistemas/irishealth-comunidade:2020.3. 0.200. 0 Se estiver a utilizar uma versão diferente (versão oficial ou mais recente), altere esta parte da especificação. O recipiente Apache será construído com o conteúdo do Dockerfile, que requer um kit WebGateway para ligar ao IRIS a partir de Apache.Para obter informações sobre como obter este kit, os parceiros da InterSystems podem visitar o site de descarregamento do WRC ou contactar o Centro de Suporte do WRC. Se tiver mais alguma questão, contacte-nos neste endereço. Modifique as seguintes partes do Dockerfile dependendo do produto que obteve. Independentemente do sistema operativo da máquina hospedeira (Windows/Ubuntu/CentOS), a plataforma será lnxubuntux64 porque o sistema operativo do recipiente httpd base é Debian. Versão ARG=2020.3. 0.200. 0 Plataforma ARG =inxubuntux64 ADD WebGateway-${versão}-${plataforma}.tar.gz /tmp/ Preparação de um certificado SSL No passo seguinte, é preparado um certificado SSL. Ao aceder à autorização OAuth2, o certificado SSL definido no servidor web é verificado para ver se corresponde ao URL a ser acedido. Não é necessário utilizar um certificado oficial; é possível utilizar o OpenSSL, etc. Introduza o nome de anfitrião no campo "Nome Comum" ao criar o certificado. Além disso, uma vez que o certificado que criou será carregado automaticamente no momento do lançamento, tem de modificar o ficheiro para que este não exija uma palavra-passe. Por favor, consulte o seguinte comando. $ openssl rsa -in cert.key.org -out cert.key Coloque os ficheiros CRT e KEY criados no mesmo diretório que o Dockerfile, com os nomes de ficheiros server.crt/servidor.key respectivamente. Além de o utilizar com o servidor web Apache, precisará de um certificado SSL para a configuração OAuth2. Não precisa de introduzir um nome de anfitrião, etc., mas precisa de criar três conjuntos. (Nas seguintes configurações, aparecem como auth.cer/auth.key , cliente.cer/cliente.key, resserver.cer/resserver.key) Construindo um estivador e iniciando um contentor de estivadores Agora está finalmente pronto! Além dos quatro ficheiros que descarregou, tem agora um conjunto de instalações web gateway e dois certificados SSL no seu diretório. Preste atenção às permissões de acesso e execução de cada ficheiro. (Por exemplo, adicionei a permissão de execução a webgateway-entrypoint.sh.) estiva-composição construção estiva-composição -d Uma vez lançado, utilize o comando do PS para verificar se ambos os contentores estão a funcionar. Nome do recipiente Apache:_web IRIS for Health:store/intersystems/irishealth-community container name:2020.3.0.200.0 (ou outro nome dependendo do conjunto) Agora tente aceder ao portal de gestão nas seguintes três formas. Se o terceiro método funcionar, a sua configuração SSL através do servidor web Apache é um sucesso! http://[nome anfitrião]:52773/csp/sys/UtilHome.csp:Este URL é acedido através do Apache Privado no contentor IRIS. Não passa pelo Apache configurado. http://[hostname]/csp/sys/UtilHome.csp: Este URL fornece acesso ao portal de gestão através do Apache configurado. https://[hostname]/csp/sys/UtilHome.csp: Este URL fornece acessoao portal de gestão utilizando uma ligação SSL via Apache, que configurae. Criação de uma configuração SSL Agora que a IRIS for Health está a funcionar e temos acesso ao portal de gestão, vamos criar a configuração SSL para os preparativos finais. Aceda ao Portal de Gestão -> Administração do Sistema -> Configuração SSL/TLS de Segurança -> e crie três configurações SSL utilizando os três pares de chaves de certificado que preparou. Pode escolher o nome que quiser, mas neste artigo utilizaremos SSL4AUTH/SSL4CLIENT/SSL4RESSERVER, de acordo com artigos anteriores sobre AAuth2.

    *Sobre a partilha de diretórios entre anfitriões e contentores Especificar os seguintes volumes no ficheiro de composição de estiva indica a localização atual do diretório de anfitriões = /ISC no recipiente. Utilize este diretório ao especificar o ficheiro do certificado nas definições acima, etc.

    Volumes:
      - .:/ Isc
    

    Este diretório conterá não só ficheiros de ficheiros, mas também ficheiros de base de dados IRIS e ficheiros de configuração. Consulte o documento "Persistente %SYS for Persistent Instance Data Storage" para obter mais informações. Configuração OAuth2 na IRIS para a Saúde Agora é hora de entrar nos detalhes do acesso ao IRIS para a Saúde usando OAuth2! Configurar o servidor de autorização OAuth2 Primeiro, vamos configurar o servidor de autorização OAuth2! Vá ao Portal de Gestão → Administração do Sistema → Segurança → OAuth 2.0 → Server. Siga as instruções abaixo para configurar as definições. Definições no separador "Geral" Ponto final do transmissor: Nome anfitrião Insira o nome de anfitrião. Ponto final do transmissor: Prefixo Pode introduzir o valor da sua escolha, mas aqui definimo-lo como "authserver". Tipos de subvenções apoiadas Neste artigo, só usaremos o "Código de Autorização", mas se quiser testar outros "Tipos de subvenções", por favor adicione uma marca de verificação. Adicione também uma marca de verificação à "Autorização JWT" SSL/TLS de configuração Especifique a configuração SSL que acabou de adicionar.

    No separador "Âmbitos", clique em "Adicionar um âmbito suportado" para os adicionar. Mais tarde, o ecrã de início de sessão de código de autorização apresentará a "descrição" que escreveu aqui.

    Não altere o separador "Intervalos" a partir do valor predefinido. No separador "Definições JWT", vamos selecionar "RS512" como algoritmo de assinatura.

    No último separador "Personalização", altere a especificação "Token Class Generation" para %OAuth2.Server.JWT.

    Uma vez introduzido a informação, clique no botão "Guardar" para guardar a configuração. Agora que tem a configuração necessária para que a IRIS for Health funcione como um servidor de autorização OAuth2, está pronto para tentar! Vamos tentar aceder-lhe do Carteiro e ver se conseguimos um sinal de acesso! No entanto, antes de o fazermos, temos de realizar duas outras configurações. Adicionar uma descrição do cliente Primeiro, adicione a informação do Carteiro a que pretende aceder como cliente OAuth2. O registo do cliente OAuth2 pode ser adicionado através de registo dinâmico ou outros métodos. Clique em "Descrição do Cliente" na página de configuração do servidor para continuar.

    Clique em "Criar descrição do cliente" para adicionar uma entrada. Siga as instruções abaixo para criar uma subscrição do cliente. Definições no separador "Geral" Nome Insira um nome à sua escolha. Neste caso, escolhemos "carteiro". Tipo de Cliente Selecione "Confidencial" Redirecionamento de URL Clique no botão "Adicionar URL" para adicionar um URL de redirecionamento para o Carteiro. https://www.getpostman.com/oauth2/callback como URL de redirecionamento para carteiro. Tipos de subvenções apoiadas Especifique o mesmo "Código de Autorização" que foi configurado nas definições do servidor de autorização OAuth2. (Predefinição) Adicione um controlo se quiser testar outros tipos de bolsas também. No entanto, as definições devem ser as mesmas que a configuração do servidor de autorização. Verifique também a caixa "Autorização JWT". Especificar aqui Algoritmo de assinatura autenticado Verifique "autorização JWT" ao abrigo de tipos de subvenção suportados para poder selecioná-la. Selecione "RS512".

    Uma vez inserida a informação, clique no botão "Guardar" para guardar a descrição do cliente. Clique no separador "Referências ao Cliente" para ver o ID do cliente e a chave privada do cliente para esta entrada. Você vai precisar desta identificação e chave privada quando fizer testes do POSTMAN.

    Adicionar uma aplicação web Deve ser adicionado outro parâmetro importante antes de aceder ao mesmo a partir do POSTMAN. O ecrã de configuração do servidor de autorização OAuth2 determinou que o ponto final para esta configuração é https:///authserver/oauth2. Para que o acesso a este ponto final seja tratado corretamente pela IRIS, precisamos de adicionar uma aplicação web para esta rota URL.

    Vá à Administração do Sistema→SSecurity →Applicações→Web Applications, e clique em "Criaruma nova aplicação Web".

    É fornecido um modelo de aplicação web OAuth2, por isso selecione primeiro "/oauth2" em "Copy from". Definições de "Editar aplicações web" Cópia de "/oauth2": Selecione sempre este primeiro na lista de drop-down. Nome /authserver/oauth2 Ativação Verifique o botão de rádio "REST".

    Depois de introduzir cada valor, guarde-o.

    Teste OAuth2 do POSTMAN Vamos testá-lo do CARTMAN. Os testes também podem ser feitos a partir de outras ferramentas ou do próprio programa. A explicação detalhada do POSTMAN está fora do âmbito deste artigo, mas um ponto a notar é que a verificação do certificado SSL deve ser alterada para OFF nas definições do POSTMAN.

    Depois de criar um novo pedido no POSTMAN, selecione "OAuth 2.0" no separador TIPO DE PERMISSÃO e clique em "Obter Novo Token de Acesso".

    No ecrã seguinte, insira os valores da seguinte forma. Configurações「GET NOVO TOKEN DE ACESSO」 Nome simbólico Insira um nome à sua escolha. Tipo de subvenção Escolha "Código de Autorização". URL de retorno https://www.getpostman.com/oauth2/callback

    Auth URL https:///authserver/oauth2/authorize Insira o valor do ponto final +/authorize. Ao adicionar ?ui_locales=ja, pode exibir o ecrã de login em japonês. Auth Token URL https:///authserver/oauth2/token. Introduza o valor do ponto final +/token. ID do cliente Introduza o ID do cliente apresentado no separador Referências ao Cliente depois de guardar a descrição do cliente. Segredo do Cliente Introduza a chave privada do cliente, que é apresentada no separador Referências ao Cliente depois de guardar a descrição do cliente. Campo Introduza o âmbito guardado na configuração do servidor de autorização, por exemplo "scope1". Também pode especificar vários campos separados por espaços. Estado Introduza o parâmetro de estado "Estado", que é utilizado para contramedidas contra o CSRF. Não é explicitamente usado, mas não pode ser deixado vazio, por isso entramos numa corda arbitrária.

    Depois de introduzir as definições e clicar no botão "Request Token", verá o ecrã de login como mostrado abaixo.

    Tente iniciar sedução com a informação do utilizador (por exemplo, _SYSTEM) que tem acesso ao portal de gestão. No ecrã seguinte após o início de sessão, pode decidir conceder permissões a esta aplicação. Depois de clicar em "Permitir", se o token de acesso for apresentado no ecrã seguinte, como mostrado abaixo, o teste de aquisição de token de acesso é bem sucedido!

    Teste OpenID Connect IRIS for Health pode realizar o processamento de autorização OAuth2, bem como o processamento de autenticação compatível OpenID Connect.Para mais detalhes consulte este documento. Nesta configuração, o OpenID Connect está ativado, por isso vamos testar se também conseguimos obter o token OpenID Connect ID! É fácil de implementar. No ecrã GET NEW ACCESS TOKEN, adicione "openid" ao seu âmbito e faça um pedido.

    O OpenID Connect também será apresentado na página de pedido de permissão. Depois de iniciar sessão e dar as suas permissões, certifique-se de que também obtém um token de identificação (id_token) quando vir o ecrã seguinte. (Pode ser necessário rolar.)

    Conseguiu o sinal de acesso e id_token? Embora alguns preparativos, como certificados, exijam um pouco de tempo e esforço, poderíamos construir um servidor de autorização OAuth2 com tal simplicidade usando IRIS para a Saúde, uma plataforma de base de dados. Na próxima parte desta série, vou finalmente mostrar-lhe como construir um repositório FHIR, registar o repositório FHIR como um servidor de recursos OAuth2, e mostrar-lhe como descansar o repositório FHIR usando um token de acesso OAuth2 da POSTMAN. Ir para a publicação inicial escrita por @Shintaro Kaminaka

    0
    0 70
    Artigo Danusa Calixto · Out. 27, 2022 4m read

    Digamos que eu esteja desenvolvendo uma aplicação web que usa o IRIS como back-end. Estou trabalhando nela com acesso não autenticado. Está chegando a hora em que eu gostaria de implantar para os usuários, mas preciso adicionar a autenticação primeiro. Em vez de usar a autenticação padrão de senha do IRIS, quero que os usuários façam login com o Login Único (single sign-on - SSO, na sigla em inglês) da minha organização ou outro provedor de identidade popular, como Google ou GitHub. Li que o OpenID Connect é um padrão de autenticação comum e compatível com o IRIS. Qual é a maneira mais simples

    0
    0 64
    Anúncio Evgeny Shvarov · Nov. 16, 2021

    Olá Desenvolvedores!

    Aqui estão os bônus tecnológicos para o Concurso de Segurança 2021 que irão fornecer mais pontos para seus projetos:

    • Uso de Autenticação Básica - 2
    • Uso de Autenticação Bearer/JWT - 3
    • Uso de OAuth 2.0 - 5
    • Uso de componentes de Autorização - 2
    • Uso de Autitoria - 2
    • Uso de Criptografia de Dados - 2
    • Uso de contêiner Docker - 2 
    • Implantação com pacote ZPM - 2
    • Demonstração Online - 2
    • Validação da Qualidade de Código - 1
    • Artigo na Comunidade de Desenvolvedores - 2
    • Vídeo no YouTube - 3

    Vejam os detalhes abaixo.<--break-><--break->

    0
    0 68
    Artigo Vinicius Maranhao Ribeiro de Castro · Dez. 21, 2020 4m read

    Nesta série de artigos de três partes, é mostrado como você pode usar o IAM para simplesmente adicionar segurança, de acordo com os padrões do OAuth 2.0, a um serviço não autenticado anteriormente implantado no IRIS.

    Na primeira parte, foram fornecidos alguns conhecimentos sobre o OAuth 2.0, juntamente com algumas definições e configurações iniciais do IRIS e IAM, para facilitar a compreensão de todo o processo de proteção dos seus serviços.

    Esta parte, agora, discutirá e mostrará em detalhes as etapas necessárias para configurar o IAM para validar o token de acesso presente na solicitação de entrada e encaminhar a solicitação para o back-end se a validação for bem-sucedida.

    A última parte desta série discutirá e demonstrará as configurações necessárias para o IAM gerar um token de acesso (atuando como um servidor de autorização) e validá-lo, junto com algumas considerações finais importantes.

    Se você quiser testar o IAM, entre em contato com seu representante de vendas InterSystems.

    Cenário 1: IAM como um validador de token de acesso

    Neste cenário, será usado um servidor de autorização externo que gera um token de acesso em formato JWT (JSON Web Token). Este JWT é assinado usando o algoritmo RS256 junto com uma chave privada. Para verificar a assinatura do JWT, a outra parte (neste caso, o IAM) precisa ter a chave pública, fornecida pelo servidor de autorização.

    Este JWT gerado pelo servidor de autorização externo também inclui, em seu corpo, uma declaração chamada “exp” contendo o carimbo de data/hora (timestamp) de quando esse token expirará, e outra declaração chamada “iss” contendo o endereço do servidor de autorização.

    Portanto, o IAM precisa verificar a assinatura do JWT com a chave pública do servidor de autorização e o carimbo de data/hora de expiração contido na declaração "exp" dentro do JWT antes de encaminhar a solicitação ao IRIS.

    Para configurar isso no IAM, vamos começar adicionando um plugin chamado “JWT” ao nosso “SampleIRISService” no IAM. Para isso, acesse a página Services do IAM e copie o id do “SampleIRISService”, que usaremos posteriormente.

    Depois disso, vá em Plugins, clique no botão “New Plugin”, localize o plugin “JWT” e clique em Enable.

    Na página seguinte, cole o id do “SampleIRISService” no campo “service_id” e selecione a caixa “exp” no parâmetro “config.claims_to_verify”.


    Observe que o valor do parâmetro “config.key_claim_name” é “iss”. Vamos usar isso mais tarde.

    Em seguida, clique no botão “Create”.

    Feito isso, vá até a seção “Consumers” no menu à esquerda e clique em nosso “ClientApp” criado anteriormente. Acesse a aba “Credentials” e clique no botão “New JWT Credential”.

    Na página seguinte, selecione o algoritmo usado para assinar o JWT (neste caso RS256) e cole a chave pública no campo “rsa_public_key” (esta é a chave pública fornecida a você pelo servidor de autorização em formato PEM).

    No campo “key”, você precisa inserir o conteúdo da declaração JWT que você inseriu no campo “config.key_claim_name” ao adicionar o plugin JWT. Portanto, neste caso, preciso inserir o conteúdo da declaração iss do meu JWT, que, no meu caso, é o endereço do servidor de autorização.

    Em seguida, clique no botão “Create”.

    Dica: para fins de depuração, existe uma ferramenta on-line de decodificação de JWT que você pode usar para verificar as declarações e seus valores e verificar a assinatura colando a chave pública. Aqui está o link desta ferramenta on-line: https://jwt.io/#debugger

    Agora, com o plugin JWT adicionado, não é mais possível enviar a solicitação sem uma autenticação. Como você pode ver abaixo, em uma simples solicitação GET, sem autenticação, para a URL

    http://iamhost:8000/event/1

    retorna uma mensagem não autorizada juntamente com o código de status “401 Não autorizado”.

    Para obter os resultados do IRIS, precisamos adicionar o JWT à solicitação.

    Portanto, primeiro precisamos solicitar o JWT ao servidor de autorização. O servidor de autorização personalizado que estamos usando aqui retorna um JWT se uma solicitação POST for feita junto com alguns pares de valores-chave no corpo, incluindo informações de usuário e cliente, para a seguinte URL:

    https://authorizationserver:5001/auth

    Isto é como se parece essa solicitação e a sua resposta:

    Em seguida, você pode adicionar o JWT obtido na resposta abaixo no cabeçalho de autorização como um Bearer Token e enviar uma solicitação GET para a mesma URL usada anteriormente:

    http://iamhost:8000/event/1

    Ou você também pode adicioná-lo como um parâmetro de querystring, com a chave de querystring sendo o valor especificado no campo “config.uri_param_names” ao adicionar o plugin JWT que, neste caso, é “jwt”:

    Finalmente, existe também a opção de incluir JWT na solicitação como um cookie, se algum nome for inserido no campo “config.cookie_names”.

    Continue lendo até a terceira e última parte desta série para entender as configurações necessárias para o IAM gerar um token de acesso e validá-lo, junto com algumas considerações finais importantes.

    0
    0 222
    Artigo Vinicius Maranhao Ribeiro de Castro · Out. 7, 2020 4m read

    Introdução

    Hoje em dia existem muitas aplicações que estão usando o Open Authorization framework (OAuth) para acessar recursos de todos os tipos de serviços de maneira segura, confiável e eficiente. O InterSystems IRIS já é compatível com a estrutura OAuth 2.0, na verdade, há um ótimo artigo na comunidade sobre OAuth 2.0 e InterSystems IRIS no seguinte link aqui.

    No entanto, com o advento das ferramentas de gerenciamento de API, algumas organizações estão usando-as como um único ponto de autenticação, evitando que solicitações não autorizadas cheguem aos serviços de downstream e desacoplando as complexidades de autorização/autenticação do próprio serviço.

    Como você deve saber, a InterSystems lançou sua ferramenta de gerenciamento de API, chamada InterSystems API Management (IAM), que está disponível com a licença IRIS Enterprise (mas não com o IRIS Community Edition). Aqui esta outra ótima postagem na comunidade apresentando o InterSystems API Management.

     Esta é a primeira parte de uma série de artigos de três partes que mostram como você pode usar o IAM para simplesmente adicionar segurança, de acordo com os padrões do OAuth 2.0, a um serviço não autenticado implantado no IRIS anteriormente.

    Nesta primeira parte, serão fornecidos alguns antecedentes do OAuth 2.0 juntamente com algumas definições e configurações iniciais do IRIS e IAM para facilitar a compreensão de todo o processo de proteção de seus serviços.

    Após a primeira parte, esta série de artigos abordará dois cenários possíveis para proteger seus serviços com IAM. No primeiro cenário, o IAM validará apenas o token de acesso presente na solicitação de entrada e encaminhará a solicitação para o backend se a validação for bem-sucedida. No segundo cenário, o IAM irá gerar um token de acesso (atuando como um servidor de autorização) e validá-lo.

    Portanto, a segunda parte irá discutir e mostrar em detalhes as etapas necessárias para configurar o cenário 1 e a terceira parte irá discutir e demonstrar as configurações do cenário 2, juntamente com algumas considerações finais.

    Se você quiser testar o IAM, entre em contato com seu representante de vendas da InterSystems.

    OAuth 2.0 - A Experiência

    Cada fluxo de autorização OAuth 2.0 consiste basicamente em 4 partes:

    1. Usuário
    2. Cliente
    3. Servidor de Autorização
    4. Proprietário do Recurso

    Para simplificar, este artigo usará o fluxo OAuth “Credenciais da Senha do Proprietário do Recurso”, mas você pode usar qualquer fluxo OAuth no IAM. Além disso, este artigo não especificará nenhum escopo.

    Nota: Você só deve usar o fluxo de Credenciais da Senha do Proprietário do Recurso quando a aplicação cliente for altamente confiável, pois ela lida diretamente com as credenciais do usuário. Na maioria dos casos, o cliente deve ser uma aplicação primária.

    Normalmente, o fluxo de Credenciais da Senha do Proprietário do Recurso segue estas etapas:

    1. O usuário insere as credenciais (por exemplo, nome de usuário e senha) na aplicação cliente
    2. A aplicação cliente envia as credenciais do usuário junto com sua própria identificação (id do cliente e segredo do cliente, por exemplo) para o servidor de autorização. O servidor de autorização valida as credenciais do usuário e a identificação do cliente e retorna um token de acesso
    3. O cliente usa o token para acessar recursos no servidor de recursos
    4. O servidor de recursos valida o token de acesso recebido antes de retornar qualquer informação ao cliente

    Com isso em mente, existem dois cenários em que você pode usar o IAM para lidar com o OAuth 2.0:

    1. O IAM atuando como um validador, verificando o token de acesso fornecido pela aplicação cliente, encaminhando a solicitação para o servidor de recursos apenas se o token de acesso for válido. Neste caso, o token de acesso seria gerado por um servidor de autorização de terceiros
    2. O IAM atua como um servidor de autorização, fornecendo token de acesso ao cliente, e como um validador de token de acesso, verificando o token de acesso antes de redirecionar a solicitação ao servidor de recursos.

    Definições de IRIS e IAM

    Nesta postagem, será utilizado uma aplicação IRIS Web denominada “/SampleService”. Como você pode ver na captura de tela abaixo, este é um serviço REST não autenticado implantado no IRIS:

    Adicionalmente, é configurado um serviço chamado “SampleIRISService” no lado do IAM contendo uma rota, como você pode ver na imagem abaixo:

    Além disso, é configurado um consumidor chamado “ClientApp” no IAM, inicialmente sem nenhuma credencial, para identificar quem está chamando a API no IAM:

    Com as configurações acima, o IAM faz proxy para o IRIS a cada solicitação GET enviada para a seguinte URL:

    http://iamhost:8000/event

    Neste ponto, nenhuma autenticação é usada ainda. Portanto, se enviarmos uma solicitação GET simples, sem autenticação, para a URL

    http://iamhost:8000/event/1

    obtemos a resposta desejada.

    Neste artigo, vamos usar uma aplicação chamada “PostMan” para enviar solicitações e verificar as respostas. Na captura de tela abaixo do PostMan, você pode ver a solicitação GET simples junto com sua resposta.

    Continue lendo até a segunda parte desta série para entender como configurar o IAM para validar os tokens de acesso presentes nas solicitações de entrada.

    0
    1 191