Neoid

Documentação Técnica Neoid

O que é o OAuth 2.0?

No modelo tradicional de autenticação cliente-servidor, o cliente solicita um acesso a um recurso restrito no servidor através da autenticação usando as credenciais do usuário. Para fornecer acesso a aplicativos de terceiros, o usuário(proprietário do recurso) compartilha suas credenciais com a terceira parte. Isso cria vários problemas e limitações:

  1. Aplicativos de terceiros necessitam armazenar as credencias do usuário para uso futuro, geralmente uma senha;
  2. Servidores são obrigados a suportar autenticação por senha, vulnerabilidades de segurança inerentes às senhas;
  3. Aplicativos de terceiros obtem acesso excessivo ao recursos protegidos do usuário, sem o usuário conseguir restringir a duração deste acesso ou o conjunto de recursos a serem acessados;
  4. Proprietários de recursos não podem revogar o acesso a um terceiro individualmente sem revogar o acesso a todos os terceiros, e faz isso alterando suas credenciais;
  5. Comprometimento de qualquer aplicativo de terceiros resulta em comprometimento da senha do usuário final e todos os dados protegidos por senha.

OAuth resolve esses problemas introduzindo uma camada de autorização e separando o papel do cliente e do usuário. No OAuth, o cliente solicita acesso a recursos controlados pelo usuário e hospedado pelo servidor, neste caso será emitido um conjunto diferente de credenciais das do usuário. Em vez de usar as credenciais do usuário para acessar recursos, o cliente obtém um token de acesso - uma string que denota escopo específico, tempo de vida e outros atributos de acesso. Tokens de acesso são emitidos para clientes de terceiros por um servidor de autorização com o aprovação do usuário. O cliente usa o token de acesso para acessar os recursos protegidos hospedados pelo servidor.

O OAuth2.0 divide o universo de aplicações em duas categorias: confidenciais e públicas. Confidenciais são aplicações capazes de armazenar, de forma segura, suas credenciais de acesso. Ex: aplicação web hospedada em servidor web. Já as aplicações Públicas não são capazes de armazenar de forma segura suas credenciais de acesso. Ex: aplicações mobile, desktop e SPA (Single Page Application).

Um dos pontos críticos do OAuth diz respeito ao cadastramento das aplicações, mais especificamente ao comprometimento de client_secret, possibilitando que aplicações maliciosas se passem por aplicações previamente cadastradas. Assim, não é recomendado que aplicações categorizadas pelo OAuth como Públicas portem uma client_secret.

Fluxo de Protocolo

Abaixo segue, em alto nível, o fluxo do OAuth 2.0 descrevendo a interação entre as partes:

  1. O cliente solicita autorização do dono do certificado. O pedido de autorização pode ser feito diretamente para o proprietário do recurso, ou de preferência indiretamente via autorização tendo o servidor como intermediário.
  2. O cliente recebe uma concessão de autorização (CODE), que é uma credencial representando a autorização do proprietário do recurso, expressa usando um dos quatro tipos de concessões definidos na especificação ou usando um tipo de concessão de extensão. O tipo de concessão de autorização depende do método utilizado pelo cliente para solicitar autorização e os tipos suportados pelo servidor de autorização.
  3. O cliente solicita um token de acesso ao autenticar com o servidor de autorização e apresentando a concessão de autorização( CODE )
  4. O servidor de autorização autentica o cliente e valida a concessão de autorização e, se for válido, emite um token de acesso.
  5. O cliente utiliza esse token para realizar uma( ou várias ) assinatura(s).

API - Serviços obrigatórios :

Os serviços abaixo são necessários para realizar a integração com o NEOID via OAuth2:

Cadastro de Aplicação com Certificado :

Serviço de auto-cadastro de uma aplicação junto ao PSC, sendo que a aplicação utilizará um certificado SSL ICP-Brasil para assinar os dados enviados.


    .Path : https://homneoid.estaleiro.serpro.gov.br/smartcert-api/v0/oauth/application_cert

    .Método HTTPS: POST

    .Cabeçalho :

    .Content-type : application/jwt ;

    .Accept : application/json ;

    Entrada:
            
        JWT na requisição(raw):

            Atributos do payload:
            name - nome da aplicação - Tipo String;
            comments - descrição da aplicação - Tipo String;
            url_base - a url da aplicação - Tipo String;
            redirect_uris - lista de até 3 urls para redirect no oauth - Tipo JSON array de string;
            aud – valor fixo :  neoid - Tipo String.

        - O JWT deve ser assinado usando RS256 (RSA WithSHA256);

            - url_base e as redirect_uris devem ser derivadas do campo CN do certificado ;
            - jwt deve conter o header "x5c", um JSON array de string contendo o certificado utilizado para a assinatura ;
            - o certificado deve estar no formato PEM ;
            - as uris devem ser https e não podem conter # ou * ;

    Obs: Deve-se utilizar um certificado de equipamento ICP-Brasil válido.


    Saída:
            
        .Parâmetros : formato "application/json;charset=UTF-8" :

        .status, obrigatório, "success" para sucesso - Tipo String;

        .message,obrigatório, mensagem com informações adicionais - Tipo String;

        .clientId - Tipo string;

        .clienteSecret - Tipo string.

    Exemplo:

    {
        "status": "success",

        "message": "Aplicação cadastrada com sucesso",

        "clientId": "",

        "clientSecret": ""
    }


    

Tabela de Erros:

    Claim (x5c) do header do JWS contendo o certificado é obrigatório

    HTTP status code 412

    {"code": "CERTIFICADO_OBRIGATORIO", "msg": "Claim (x5c) no Header do JWS contendo o Certificado em Base64 (PEM) é obrigatório.", "debug":""}

    O valor esperado da claim (x5c) não foi encontrado

    HTTP status code 412

    {"code": "VALOR_INVALIDO_CLAIM_X5C", "msg": "Valor da claim (x5c) no Header do JWS está inválido, esperado um array de strings contendo o Certificado em Base64 (PEM).", "debug":""}

    Assinatura JWS inválida

    HTTP status code 412

    {"code": "JWS_INVALIDO", "msg": "Token inválido", "debug":""}

    Certificado inválido

    HTTP status code 412

    {"code": "CERTIFICADO_INVALIDO", "msg": "Certificado inválido.", "debug":""}

    O certificado informado não é do tipo Equipamento ICP-Brasil

    HTTP status code 412

    {"code": "CERTIFICADO_EQUIPAMENTO_INVALIDO", "msg": "O certificado precisa ser do tipo Certificado de Equipamento ICP-Brasil.", "debug":""}

    Não foi possível encontrar uma cadeia de certificação ICP-Brasil para o certificado informado

    HTTP status code 412

    {"code": "CADEIA_DE_CERTIFICADOS_ICP_BRASIL_NAO_ENCONTRADA", "msg": "Cadeia de certificados ICP-Brasil não encontrada.", "debug":""}

    O certificado informado está expirado ou é inválido

    HTTP status code 412

    {"code": "CERTIFICADO_EXPIRADO_OU_INVALIDO", "msg": "O certificado encontra-se expirado ou é invalido: ... : ...", "debug":""}

    O certificado informado se encontra revogado

    HTTP status 412

    {"code": "CADASTRO_APLICACAO_CERTIFICADO_REVOGADO", "msg": "O certificado informado encontra-se revogado: ... : ..."", "debug":""}

    Não foi possível verificar revogação do certificado informado

    HTTP status 412

    {"code": "CADASTRO_APLICACAO_CERTIFICADO_REVOGACAO_NAO_VERIFICADA", "msg": "Não foi possível verificar a revogação do certificado informado: ... : ...", "debug":""}

    Campo Obrigatório não informado

    HTTP status code 412

    {"code": "CAMPO_OBRIGATORIO", "msg": O campo ... é obrigatório", "debug":""}

    Deve ser informado ao menos 1 URI para redirect

    HTTP status code 412

    {"code": "PELO_MENOS_UMA_REDIRECT_URI", "msg": "Informe pelo menos uma redirect URI", "debug":""}

    Só é possível cadastrar 3 URIs para redirect

    HTTP status code 412

    {"code": "MAXIMO_TRES_REDIRECT_URIS", "msg": "Informe no máximo 3 redirect URIs", "debug":""}

    O Nome da aplicação informada já se encontra cadastrado

    HTTP status code 412

    {"code": "APLICACAO_OAUTH_NOME_JA_CADASTRADO", "msg": "Já existe uma aplicação cadastrada com o nome informado", "debug":""}

    URI informada não é considerada valida

    HTTP status code 412

    {"code": "URI_INVALIDA", "msg": "URI inválida: ...", "debug":""}

    Protocolo HTTPS obrigatório na URI

    HTTP status code 412

    {"code": "URI_HTTPS_OBRIGATORIO", "msg": "O protocolo da URI deve ser https: ...", "debug":""}

    Redirect URI informada não se encontra na extensão Subject Alternative Names

    HTTP status code 412

    {"code": "URI_NAO_CORRESPONDE_SUBJECT_ALT_NAME_CERTIFICADO", "msg": "URI não deriva do conjunto de subject alternative names do certificado: ...", "debug":""}

    A URL base informada já se encontra cadastrada

    HTTP status code 412

    {"code": "APLICACAO_OAUTH_URL_BASE_JA_CADASTRADA", "msg": "Já existe uma aplicação cadastrada com URL Base informada", "debug":""}

    Erro na leitura do certificado informado

    HTTP status code 412

    {"code": "FALHA_AO_LER_CERTIFICADO", "msg": "Falha ao ler certificado", "debug":""}

    Erro interno do processo de cadastro da aplicação

    HTTP status code 500

    {"code": "FALHA_CADASTRO_APLICACAO", "msg": "Erro interno no cadastro da aplicação", "debug":""}


Código de Autorização (Authorization Code Request):

Serviço para obter do titular a autorização de uso da sua chave privada.

             

    .Path :https://homneoid.estaleiro.serpro.gov.br/smartcert-api/v0//oauth/authorize;

    .Método HTTPS : GET;

    Entrada:

    .Parâmetros da requisição: concatenados após o Path como parâmetros http query, usando o formato "application/x-www-form-urlencoded":

    .response_type : obrigatório, valor "code";

    .client_id : obrigatório, deve conter a identificação da aplicação;

    .redirect_uri : opcional, deve ter a URI para redirecionar o usuário de volta para a aplicação de origem. A URI deve estar na lista de URI's autorizadas para a aplicação. Deve ser URL ENCODED. Se não informado, será considerada a primeira URI cadastrada para a aplicação;

    .state : opcional, é retornado sem modificações para aplicação de origem;

    .scope : opcional, se não informado, será considerado "single_signature".

    (ver lista de escopos abaixo). Possíveis valores para o parâmetro:

    . single_signature : token que permite a assinatura de apenas um conteúdo (hash), sendo invalidado apos a sua utilização;

    .multi_signature: token que permite a assinatura de multiploshashes em uma única requisicao, sendo invalidado apos a sua utilização;

    .code_challenge : obrigatório. É um código gerado por um PKCE. Mais informações em https://www.oauth.com/oauth2-servers/pkce/ (ver RFC 7636) : https://auth0.com/docs/api-auth/tutorials/authorization-code-grant-pkce#1-create-a-code-verifier

    .code_challenge_method : obrigatório, valor "S256" (ver RFC 7636).

    Exemplo:https://homneoid.estaleiro.serpro.gov.br/smartcert-api/v0/oauth/authorize/?response_type=code&client_id=64e587fa-4f30-487d-96f0-44e6b14ff620&scope=single_signature&redirect_uri=https%3A%2F%2Fhom-neoid.serpro.gov.br%2F1&code_challenge=aRU8irrNrwu8U8cH1nYTvdcFNujZo5_Gri5j02xmXUU&code_challenge_method=S256&state=testando123 


    Exemplo de geração do code_challenge

    Retorno:

    É retornado um URI de redirecionamento com dois parâmetros http query, usando o formato "application/x-www-form-urlencoded":

    .code : obrigatório, código de autorização gerado pelo PSC, a ser usado na solicitação do token de acesso;

    .state : obrigatório caso tenha sido informado na requisição, deverá conter o que foi enviado na

    Exemplo:                                      

    https://hom-neoid.serpro.gov.br/1?code=4011c5ef-8378-4890-ac31-9498bdc0c865&state=testando123



                         

Tabela de Erros:


    Parâmetro(s) requerido(s) não informado(s): ...

    HTTP status code 412

    Parâmetro(s) duplicado(s) informado(s): ...

    HTTP status code 412

    Parâmetro(s) com valor(es) inválido(s): ...

    HTTP status code 412

    Não foi possível identificar a aplicação cliente.

    HTTP status code 412

    O parâmetro code_challenge deve ter no mínimo ... caracteres.

    HTTP status code 412

    Redirect uri inválida para a aplicação.

    HTTP status code 412

    Parâmetro(s) com valor(es) inválido(s): ...

    HTTP status code 412

    Erro interno no processamento da requisição.

    HTTP status code 500
    

Token de Acesso :

Após a obtenção de código de autorização, o token de acesso deve ser solicitado com parâmetros no formato "application/x-www-form-urlencoded" .


    Path : https://homneoid.estaleiro.serpro.gov.br/smartcert-api/v0/oauth/token ;

    .Método HTTPS : POST;

    Entrada:

        .Parâmetros da requisição : formato "application/x-www-formurlencoded"

        .grant_type : obrigatório, valor "authorization_code" - Tipo String;

        .client_id : obrigatório, deve conter a identificação da aplicação - Tipo String;

        .client_secret : opcional, sendo obrigatório se a aplicação não utilizar certificado ICP-Brasil - Tipo String;

        .code : deve conter código de autorização retornado do Serviço Código de Autorização como redirect_uri - Tipo String;

        .redirect_uri : opcional, deve ser igual ao informado no Serviço Código de Autorização - Tipo String;

        .code_verifier : obrigatório, correspondendo a code_challenge enviado na Requisição de Código de Autorização, ver RFC 7636 - Tipo String.


    Retorno:

        .Parâmetros de retorno : formato "application/json;charset=UTF-8"

        .access_token : obrigatório, valor do token de acesso - Tipo String;

        .token_type : obrigatório, valor "Bearer" - Tipo String;

        .expires_in : obrigatório, valor inteiro com validade do token em segundos. Não deve ultrapassar o

        valor 300 (5 minutos) - Tipo inteiro;

        .scope : opcional, deve ser informado se o escopo retornado for diferente do solicitado pela aplicação - Tipo String.


    Exemplo:

    { 

       "access_token": "eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJuZW9pZCIsImF1ZCI6Im5lb2lkIiwic3ViIjoiNjRlNTg3ZmEtNGYzMC00ODdkLTk2ZjAtNDRlNmIxNGZmNjIwIiwiaWF0IjoxNTI4OTgyMDYyLCJqdGkiOiI4N2NhYTkzOS0wMjgxLTQ1YjktODA3Mi1lNjI1NDkzN2JlMzYiLCJoYXQiOiJNVEV6T1RJQUFBQUFBQUFBQUFBQUFPYXBWdEJnenp0b2JxZFY5Sk5CemRCVVVQcHlhdGtMWTJ2UjNDTFJmQy8wQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBRC8vLy8vLy8vLy93PT0ifQ.qsUtA4hBWGtM5HYuMcLMtWtDQtdgk95Rf_sJhMbAgvEqkq0xq6e4-1QXrLfodbbOES0Jnz4RpRpdmuXOVcLcduCmstgOfPIvjqi5Ewb93zTpuGavDGCmNiFpd33T8ytdl9KhIyCVisDg8LEWIdiPscBk421zTu2Dquj4rzQGVVM1EkrCqOazeU6zxnF3gSuIOgnvxeReu6k-runIPr5F1ZAsglPsQKp-WZqmqG9gmzoNOSXSFFD3g2S5nS4zdKuOL8NH1QfJytF72Ylvifhj4Fdlz9wWLDXZwMmvQjhHmJetNnN16D1CS3PUlQq1VdStMktgoOSqQOLzUMxPuLq-gw", 

        "token_type": "BEARER", 

        "expires_in": 300, 

        "scope": "single_signature" 

    }


Tabela de erros:


    Parâmetro requerido não informado

    HTTP status code 400

    {"error": "invalid_request", "error_description": "Parâmetro(s) requerido(s) não informado(s): ...", "error_uri":""}

    Parâmetro com mais de um valor informado

    HTTP status code 400

    {"error": "invalid_request", "error_description": "Parâmetro(s) com mais de um valor informado: ...", "error_uri":""}

    Valor do parâmetro grant_type inválido

    HTTP status code 400

    {"error": "unsupported_grant_type", "error_description": "Valor do parâmetro grant_type não suportado: ...", "error_uri":""}

    Aplicação cliente informada via client_id inválida

    HTTP status code 401

    {"error": "invalid_client", "error_description": "Cliente não encontrado", "error_uri":""}

    Senha da aplicação cliente, client_secret, inválida para a aplicação informada via client_id

    HTTP status code 401

    {"error": "invalid_client", "error_description": "Falha na autenticidade do client_id e client_secret", "error_uri":""}

    Valor inválido do código de autorização (code)

    HTTP status code 400

    {"error": "invalid_grant", "error_description": "Falha na autenticidade do code", "error_uri":""}

    Código de autorização (code) expirado

    HTTP status code 400

    {"error": "invalid_grant", "error_description": "Authorization code expirado", "error_uri":""}

    Valor do parâmetro redirect_uri com encode inválido

    HTTP status code 400

    {"error": "invalid_grant", "error_description": "Encode inválido da redirect_uri", "error_uri":""}

    Valor do parâmetro redirect_uri não informado ou diferente da apresentada no requisição de autorização

    HTTP status code 400

    {"error": "invalid_grant", "error_description": "Redirect URI não apresentada ou diferente da apresentada no Authorization Request", "error_uri":""}

    Valor do parâmetro code_verifier não condiz com o valor do code_challenge informado na requisição de autorização

    HTTP status code 400

    {"error": "invalid_grant", "error_description": "Falha na autenticidade do code_challenge e code_verifier", "error_uri":""}

    O token de acesso (access_token) referente ao código de autorização (code) informado já foi gerado e/ou utilizado

    HTTP status code 400

    {"error": "invalid_grant", "error_description": "Access token encontra-se gerado ou utilizado para o code apresentado", "error_uri":""}

    Erro interno do servidor

    HTTP status code 500

    {"error": "server_error", "error_description": "Erro interno do servidor"}

Assinatura :

O hash a ser assinado deve ser um SHA256 (em base64). Se o escopo do token permitir apenas uma assinatura (sigle_signature) e for informado mais de um conteúdo, uma mensagem de erro deve ser retornada.


    .Path : https://homneoid.estaleiro.serpro.gov.br/smartcert-api/v0//oauth/signature

    .Método HTTPS : POST

    .Cabeçalho :

    .Content-type : application/json ;

    .Accept : application/json ;

    .Authorization : Bearer access_token;


        Entrada:

            .Parâmetros : formato "application/json;charset=UTF-8" :

            .hashes : conjunto com valores a serem assinados. Cada elemento do conjunto conterá:

            .id: identificador do conteúdo a ser assinado - Tipo String;

            .alias: forma legível do identificador do conteúdo - Tipo String;

            .hash: conteúdo a ser assinado - Tipo String


         Exemplo:

    { 
            "hashes":[ 

            { 
                "id": "idTeste", 

                "alias": "aliasTeste", 

                "hash": "hashTeste" (o que será assinado)
            } 

            ] 

    }


    Saída:

        .Parâmetros : formato "application/json;charset=UTF-8" :

        .status : obrigatório, "success" para sucesso;

        .message: obrigatório, mensagem com informações adicionais;

        .id : identificador do conteúdo assinado;

        .raw_signature : valor numérico em base64 da assinatura produzida.

    Exemplo:

    {         
        "signatures":[ 

            { 

                "id": "Signature request ID 1", 

                "raw-signature": "hash to sign" 

            }, 

            { 

                "id": "Signature request ID 2", 

                "raw-signature": "hash to sign" 

            } 

            { 

                "id": "Signature request ID n", 

                "raw-signature": "hash to sign" 

            }] 
    }

                    

Tabela de Erros:

    Token de acesso não informado ou inválido

    HTTP status code 401

    {"code": "JWT_INVALIDO", "msg": "Token de acesso inválido", "debug":""}

    Hash(es) para assinatura não informado(s)

    HTTP status code 412

    {"code": "ASSINATURA_DADOS_INVALIDOS", "msg": "As informações para a assinatura são obrigatórias", "debug":""}

    Token de acesso já utilizado

    HTTP status code 401

    {"code": "TOKEN_JA_UTILIZADO", "msg": "O token já foi utilizado e por isso não é mais válido", "debug":""}

    Token de acesso gerado apenas para escopo "single_signature" e mais de um hash informado

    HTTP status code 412

    {"code": "ASSINATURA_NOT_SINGLE", "msg": "Este token só permite uma assinatura do tipo single_signature.", "debug":""}

    Valor máximo de assinaturas atingido

    HTTP status code 412

    {"code": "MULTI_SIGNATURE_ASSINATURAS_MAXIMO_ATINGIDO", "msg": "O número de assinaturas simultâneas não pode ser superior a ....", "debug":""}

    Valor máximo em bytes dos hashes atingido

    HTTP status code 412

    {"code": "MULTI_SIGNATURE_TAMANHO_MAXIMO_ATINGIDO", "msg": "O tamanho do documento não pode ser superior a ... bytes.", "debug":""}

    Acesso bloqueado por limite de erro de credenciais

    HTTP status code 401

    {"code": "NAMESPACE_BLOQUEADO", "msg": "Acesso bloqueado por limite de erro de credencial", "debug":""}

    Token de acesso inválido

    HTTP status code 401

    {"code": "INVALID_ACCESS_TOKEN", "msg": "Token de acesso inválido", "debug":""}

    Erro interno do processo de assinatura

    HTTP status code 500

    {"code": "SIGN_FAIL", "msg": "Falha no processo de assinatura", "debug":""}

Insumos para a integração:

1 - Links para emissão dos certificados para testes:

2 - Fluxo para aprovação dos pedidos dos certificados abertos no item 1:
Abrir solicitação no endereço: https://atendimento.serpro.gov.br/neoid :


    Sugestão de texto:
        Solicito a aprovação do pedido de solicitação de certificado para o cliente XXX. O certificado tem a função de homologação de integração com o sistema YYYY.
        Número de Referência do Pedido:YYYYYY
        Tipo de Certificado: XXXXX 
        Ambiente da Solicitação: https://certificadoshom.serpro.gov.br/XXXXX
        Sistema: XXXXXXXXXX

2.1 - Ao instalar o apk no celular/tablet verifique antes se já possui o NEOID de produção instalado pois a instalação do apk de teste irá sobrescrever o atual.

3 - A aplicação de teste (Android) está disponível para download aqui.

Referências:

  • INSTRUÇÃO NORMATIVA No 6, DE 16 DE ABRIL DE 2018
  • https://oauth.net/2/