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.
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.
Um exemplo de troca de mensagens autenticadas é:
Uso da API Key
Com sua API Key, você pode realizar ações programaticamente no ECO-UTM:
- Insira a sua API Key no header da requisição;
- Insira o
scope
- Insira o
intended_audience
- Em caso de comunicação com outro USS, o preencha com o conteúdo campo
manager
da resposta do DSS.
- Em caso de comunicação com outro USS, o preencha com o conteúdo campo
Validator
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 |
Cria uma solicitação de voo para um espaço aéreo descrito na requisição
Headers
Bearer
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
| |
|
Response
Categoriza uma solicitação de voo por número de protocolo
Headers
Bearer
Path Param
Response
Analisa uma solicitação de voo por número de protocolo
Headers
Bearer
Path Param
Response
Headers
Bearer
Response
Headers
Bearer
Response
Busca todas as aeronaves em voo, opcionalmente incluindo compartilhadas, de um usuário identificado pelo ID enviado na requisição
Headers
Bearer
Body
{
"user_information_id": "1ed4b29e-8fe0-60aa-aefd-0242ac120019",
"shared": true
}
Campos notáveis
Response
Lista os status do voo de um usuário identificado pelo token de sessão
Headers
Bearer
Response
200
ASA
A URL base para os seguintes endpoints é http://kong.icea.decea.mil.br:64236/api/
Cria uma área no ASA dados os identificadores do polígono e usuário
Headers
Bearer
Path Param
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
}
Obter resultado da solicitação de área
Headers
Bearer
Path Param
Response
200 OK