Skip to main content

Autenticação Service Provider

API Key:

Na comunicação do BR-UTM (imagem abaixo), as requisições devem ser autenticadas e autorizadas. Devido à natureza distribuída da arquitetura, não é viável que cada provedor possua sua lógica de autenticação e autorização.

image.png

Portando, a solução proposta pela ASTM é a de um servidor de autenticação central onde os provedores obtém tokens OAuth2 codificados e assinados em JWT. O Validator da documentação abaixo checa a validade da assinatura do token, utilizando a chave pública do Auth Server.

image.png

Um exemplo de troca de mensagens autenticadas é:

image.png

Uso da API Key

Com sua API Key, você pode realizar ações programaticamente no ECO-UTM:

  1. Insira a sua API Key no header da requisição;
  2. Insira o scope 
  3. Insira o intended_audience
    1. Em caso de comunicação com outro USS, o preencha com o conteúdo campo manager da resposta do DSS.

image.png

Validator

image.png

Implementação

Código de exemplo para início da implementação do Auth Server e do Validator em Go

Código exemplo
package main

import (
	"encoding/json"
	"flag"
	"log"
	"net/http"
	"os"
	"strings"

	"github.com/golang-jwt/jwt"
)

var (
	keyFile       = flag.String("private_key_file", "auth.key", "OAuth private key file")
	publicKeyFile = flag.String("public_key_file", "auth.pem", "OAuth public key file")
)

func verifyToken(token string) (bool, error) {
	bytes, err := os.ReadFile(*publicKeyFile)
	if err != nil {
		log.Panic(err)
	}

	publicKey, err := jwt.ParseRSAPublicKeyFromPEM(bytes)
	if err != nil {
		log.Panic(err)
	}

	parts := strings.Split(token, ".")
	err = jwt.SigningMethodRS256.Verify(strings.Join(parts[0:2], "."), parts[2], publicKey)
	if err != nil {
		return false, nil
	}
	return true, nil

}

func main() {

	http.HandleFunc("/validate", func(w http.ResponseWriter, r *http.Request) {
		tokenString := r.URL.Query().Get("token")
		valid, err := verifyToken(tokenString)
		if err != nil {
			log.Panic(err)
		}

		log.Println(valid)
	})

	http.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
		
		token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
			"aud":   "aud",
			"scope": "scope",
			"iss":   "iss",
			"exp":   "exp",
			"sub":   "sub",
		})

		// Read private key
		bytes, err := os.ReadFile(*keyFile)
		if err != nil {
			log.Panic(err)
		}
		privateKey, err := jwt.ParseRSAPrivateKeyFromPEM(bytes)
		if err != nil {
			log.Panic(err)
		}

		// Sign and get the complete encoded token as a string using the secret
		tokenString, err := token.SignedString(privateKey)
		if err != nil {
			log.Panic(err)
		}

		resp := make(map[string]string)
		resp["access_token"] = tokenString
		jsonResp, err := json.Marshal(resp)
		if err != nil {
			log.Fatalf("Error happened in JSON marshal. Err: %s", err)
		}
		w.WriteHeader(http.StatusOK)
		w.Header().Set("Content-Type", "application/json")
		w.Write(jsonResp)
		return

	})

	log.Fatal(http.ListenAndServe(":9096", nil))
}

 

Com o código acima rodando na porta :9096, é necessário criar um Serviço e uma Route no Kong para torná-lo acessível:

Lista de endpoints

A lista completa de endpoints também está disponível neste arquivo OpenAPI  e nesta coleção no Insomina.

ECO-UTM

A URL base para os seguintes endpoints é http://montreal.icea.decea.mil.br:64235/


PUT /providers/user_token/{token}/assign

Associar usuário e provedor

Headers
apikey API Key disponível no BR-UTM Forms
Path Param
token
SARPAS ID do usuário
Body
{
  "data": {
    "provider_secret": "your-provider-api-key",
    "provider_id": "kong-consumer-custom-id"
    
  }
}

Campos notáveis

provider_secret API Key disponível no BR-UTM Forms
provider_id

[OPCIONAL] Custom ID do Kong associado ao Consumer

Response
200
Success
404
User not found

 


POST /providers/auth

Gerar token de autenticação

Headers
apikey API Key disponível no BR-UTM Forms
Body
{
  "data": {
    "provider_secret": "",
    "provider_id": "",
    "user_id": ""
  }
}

Campos notáveis

provider_secret API Key disponível no BR-UTM Forms
provider_id

[OPCIONAL] Custom ID do Kong associado ao Consumer

user_id

SARPAS ID do usuário

Response

204

Success

404

User not found

412

Invalid provider and user relationship

500

Internal server error

GET /user-keys/{user-id}

Aprovar token de autenticação do provedor associado ao usuário

Path Param
user-id SARPAR ID do usuário
Bearer
token Bearer token gerado
Response
200 Success
500
Error

POST /pilots/flights

Cria uma solicitação de voo para um espaço aéreo descrito na requisição

Headers
apikey API Key disponível no BR-UTM Forms
Bearer
token Bearer token gerado
Body
{
    "data": {
        "type": "/pilots/flights",
        "attributes": {
            "airplane_id": "1ed0e6d9-e88e-6812-bd5f-0242ac12001c",
            "operation": {
                "aircrafts": [
                   {
                        "id": 4,
                        "uuid": "1ed0e6d9-e88e-6812-bd5f-0242ac12001c"
                   }
                ],
                "flight": {
                    "pilots": ["QGRK"],
                    "date": {
                        "start_day": "2025-12-16",
                        "start_hour": "08:00",
                        "finish_day": "2025-12-16",
                        "finish_hour": "09:00"
                    },
                    "type": "VLOS",
                    "observations": "teste",
                    "communication": {
                        "id": "1",
                        "ats_call_type": "vhf-fm",
                        "rpa_call_type": "vhf-am",
                        "rps": [
                            {
                                "name": "1",
                                "lat": "1",
                                "lng": "1",
                                "contact_info": "1",
                                "radius": 100
                            }
                        ]
                    },
                    "sarpas_code": "OJMN",
                    "area": {
                        "asa_id": "283797ce-73e9-4395-adcf-6c6119b3f20f",
                        "takeoff_point": [-34.993236064910896,-8.02209168418088],
                        "landing_point": [-34.993236064910896,-8.02209168418088],
                        "required_route": {
                            "geojson": {
      "type": "Feature",
      "properties": {},
      "geometry": {
        "type": "Polygon",
        "coordinates": [
					[
						[
							-24.080093705511494,
							-49.0539316478104
						],
						[
							-24.081153158442177,
							-49.05006533240442
						],
						[
							-24.08503406183282,
							-49.052976909391695
						],
						[
							-24.082881359600847,
							-49.055986687210066
						],
						[
							-24.080093705511494,
							-49.0539316478104
						]
					]
				]
      }
    }
                            },
                            "flight_type": "height",
                            "flight_distance": 100
                        },
                        "documents": []
                    },
                    "basic_information": {
                        "name": "teste 2",
                        "type": "101",
                        "agree_terms": 1
                    }
                }
            }
        }
    }

Campos notáveis

provider_secret API Key disponível no BR-UTM Forms
provider_id

[OPCIONAL] Custom ID do Kong associado ao Consumer

user_id

SARPAR ID do usuário

Response
200
Success

GET /bypass/categorize/{solicitationProtocol}

Categoriza uma solicitação de voo por número de protocolo

Headers
apikey API Key disponível no BR-UTM Forms
Bearer
token Bearer token gerado
Path Param
solicitationProtocol Número de protocolo da solicitação
Response
200
Success
404
Solicitation not found
500
Error

GET /bypass/analyze/{solicitationProtocol}

Analisa uma solicitação de voo por número de protocolo

Headers
apikey API Key disponível no BR-UTM Forms
Bearer
token Bearer token gerado
Path Param
solicitationProtocol Número de protocolo da solicitação
Response
200
Success
404
Solicitation protocol not found
500
Error

GET /user-aircraft

Busca todas as aeronaves de um usuário identificado pelo token de sessão

Headers
apikey API Key disponível no BR-UTM Forms
Bearer
token Bearer token gerado
Response
200
Success

GET
/shared-aircraft-user

Busca todas as aeronaves compartilhadas com um usuário identificado pelo token de sessão

Headers
apikey API Key disponível no BR-UTM Forms
Bearer
token Bearer token gerado
Response
200
Success

POST /user/flight/aircrafts

Busca todas as aeronaves em voo, opcionalmente incluindo compartilhadas, de um usuário identificado pelo ID enviado na requisição

Headers
apikey API Key disponível no BR-UTM Forms
Bearer
token Bearer token gerado
Body
{
  "user_information_id": "1ed4b29e-8fe0-60aa-aefd-0242ac120019",
  "shared": true
}

Campos notáveis

user_information_id SARPAS ID do usuário
shared
[OPCIONAL] Incluir aeronaves compartilhadas
Response

 

200
Success

GET
/flight-status

Lista os status do voo de um usuário identificado pelo token de sessão

Headers
apikey API Key disponível no BR-UTM Forms
Bearer
token Bearer token gerado
Response

200

ASA

A URL base para os seguintes endpoints é http://kong.icea.decea.mil.br:64236/api/


POST /polygon/{polygonId}/{userUuid}

Cria uma área no ASA dados os identificadores do polígono e usuário

Headers
apikey API Key disponível no BR-UTM Forms
Bearer
token Bearer token gerado
Path Param
polygonId ID (definido pelo solicitante) do polígono criado
userUuid
SARPAS ID do usuário
Body
{
    "type": "Feature",
    "properties": {
      "poligonoId": "283797ce-73e9-4395-adcf-6c6119b3f20f",
      "perfil": "1",
      "datasHoras": "{\"date1\":\"2023-11-30\",\"date2\":\"2023-11-30\",\"hora1\":\"14:00\",\"hora2\":\"15:00\"}",
      "elevacoes": {
        "criarAreaMaximo": 10,
        "criarAreaMinimo": 0,
        "criarAreaMaximoFt": 32.8084,
        "criarAreaMinimoFt": 0,
        "criarAreaNome": "",
        "criarAreaDescricao": "",
        "alturaEditavelMetros": "10",
        "alturaEditavelPes": 32.8084,
        "dataInicio": "2025-12-12",
        "dataTermino": "2025-12-12",
        "horaInicio": "08:00",
        "horaTermino": "09:00",
        "update": []
      },
      "raio": 0,
      "altura": "10",
      "formato": "poligono",
      "contextoId": 1,
      "pontoDecolagem": {
        "latLng": {
          "lat": -24.098672973607677,
          "lng": -48.909985432572751,
          "valido": true
        },
        "unidade": "gms",
        "elevationM": 10,
        "elevationFt": 32.8084,
        "valido": true
      }
    },
    "geometry": {
      "type": "Polygon",
      "coordinates": [
					[
						[
							-24.080093705511494,
							-49.0539316478104
						],
						[
							-24.081153158442177,
							-49.05006533240442
						],
						[
							-24.08503406183282,
							-49.052976909391695
						],
						[
							-24.082881359600847,
							-49.055986687210066
						],
						[
							-24.080093705511494,
							-49.0539316478104
						]
					]
				]
    }
  }

Campos notáveis


 
Response
{
  voo_id: string
}
voo_id

GET /polygon/{solicitationProtocol}/result

Obter resultado da solicitação de área

Headers
apikey API Key disponível no BR-UTM Forms
Bearer
token Bearer token gerado
Path Param
solicitationProtocol Número de protocolo da solicitação de área
Response

200 OK