Skip to content

Commit 3ad5e54

Browse files
authored
Merge pull request #88 from itk-dev/feature/user-api-key
Add servers and sites API endpoints and let users use the API
2 parents 28a6d27 + b89bc6d commit 3ad5e54

16 files changed

Lines changed: 577 additions & 32 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
- [#88](https://github.com/itk-dev/devops_itksites/pull/88)
11+
- Let users use the API
12+
- Add security to detection results API endpoint
13+
- Add server and site collections API endpoints
1014
- [#80](https://github.com/itk-dev/devops_itksites/pull/80) 5566: Service agreements
1115
- Add security contract entity with crud controller
1216
- Add Abstract full crud controller and extend on it in some cases

README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,24 @@ The system is build so that all analyzed data can be truncated safely and rebuil
4545
by "replaying" the DetectionResults. This means that care must be taken when
4646
manually maintained data and auto updated data must have cross references.
4747

48+
## API
49+
50+
Authenticated users can access a simple read-only API – see the API documentation on `/api/docs` for details.
51+
52+
### API keys
53+
54+
Run the `app:user:set-api-key` console command to set the API for a user:
55+
56+
``` shell
57+
docker compose exec phpfpm php bin/console app:user:set-api-key <user-id>
58+
```
59+
60+
Use the API key to make an authenticated request, e.g.
61+
62+
``` shell
63+
curl --header 'accept: application/json' --header 'authorization: Apikey <the API key>' https://itksites.local.itkdev.dk/api/sites
64+
```
65+
4866
## Development
4967

5068
```sh

config/packages/api_platform.yaml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
api_platform:
2-
title: 'ITKsites Detection API'
3-
description: 'REST API for ingesting server detection results from the ITK sites server harvester. Detection results are processed asynchronously to track servers, sites, domains, packages, modules, Docker images, and git repositories.'
2+
title: 'ITKsites API'
3+
description: |
4+
REST API for ingesting server detection results from the ITK sites server harvester. Detection results are processed asynchronously to track servers, sites, domains, packages, modules, Docker images, and git repositories.
5+
6+
The API also provides read-only access to information on servers and sites created by processing detection results.
47
version: '1.0.0'
58

69
mapping:

config/packages/security.yaml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ security:
1212
entity:
1313
class: App\Entity\User
1414
property: email
15+
16+
app_api_users:
17+
chain:
18+
providers: [app_server_provider, app_user_provider]
19+
1520
firewalls:
1621
dev:
1722
pattern: ^/(_(profiler|wdt)|css|images|js)/
@@ -20,7 +25,7 @@ security:
2025
pattern: ^/api
2126
custom_authenticators:
2227
- App\Security\ApiKeyAuthenticator
23-
provider: app_server_provider
28+
provider: app_api_users
2429

2530
main:
2631
custom_authenticators:
@@ -41,7 +46,7 @@ security:
4146
# Note: Only the *first* access control that matches will be used
4247
access_control:
4348
- { path: ^/api/docs, roles: PUBLIC_ACCESS }
44-
- { path: ^/api, roles: ROLE_SERVER }
49+
- { path: ^/api, roles: [ROLE_SERVER, ROLE_USER] }
4550
- { path: ^/admin, roles: ROLE_ADMIN }
4651
# - { path: ^/profile, roles: ROLE_USER }
4752

fixtures/user.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
App\Entity\User:
22
user_admin:
3-
__construct: ["admin@example.com", "Admin", [ROLE_ADMIN]]
3+
__construct: ["Admin", "admin@example.com", [ROLE_ADMIN]]
4+
user_user:
5+
__construct: ["User", "user@example.com", [ROLE_USER]]
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DoctrineMigrations;
6+
7+
use Doctrine\DBAL\Schema\Schema;
8+
use Doctrine\Migrations\AbstractMigration;
9+
10+
/**
11+
* Auto-generated Migration: Please modify to your needs!
12+
*/
13+
final class Version20260702123347 extends AbstractMigration
14+
{
15+
public function getDescription(): string
16+
{
17+
return '';
18+
}
19+
20+
public function up(Schema $schema): void
21+
{
22+
// this up() migration is auto-generated, please modify it to your needs
23+
$this->addSql('ALTER TABLE user ADD api_key VARCHAR(255) NOT NULL');
24+
$this->addSql('CREATE UNIQUE INDEX UNIQ_8D93D649C912ED9D ON user (api_key)');
25+
}
26+
27+
public function down(Schema $schema): void
28+
{
29+
// this down() migration is auto-generated, please modify it to your needs
30+
$this->addSql('DROP INDEX UNIQ_8D93D649C912ED9D ON user');
31+
$this->addSql('ALTER TABLE user DROP api_key');
32+
}
33+
}

public/api-spec-v1.json

Lines changed: 185 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"openapi": "3.1.0",
33
"info": {
4-
"title": "ITKsites Detection API",
5-
"description": "REST API for ingesting server detection results from the ITK sites server harvester. Detection results are processed asynchronously to track servers, sites, domains, packages, modules, Docker images, and git repositories.",
4+
"title": "ITKsites API",
5+
"description": "REST API for ingesting server detection results from the ITK sites server harvester. Detection results are processed asynchronously to track servers, sites, domains, packages, modules, Docker images, and git repositories.\n\nThe API also provides read-only access to information on servers and sites created by processing detection results.",
66
"version": "1.0.0"
77
},
88
"servers": [
@@ -92,6 +92,144 @@
9292
"required": true
9393
}
9494
}
95+
},
96+
"/api/servers": {
97+
"get": {
98+
"operationId": "api_servers_get_collection",
99+
"tags": [
100+
"Server"
101+
],
102+
"responses": {
103+
"200": {
104+
"description": "Server collection",
105+
"content": {
106+
"application/json": {
107+
"schema": {
108+
"type": "array",
109+
"items": {
110+
"$ref": "#/components/schemas/Server-export"
111+
}
112+
}
113+
},
114+
"application/ld+json": {
115+
"schema": {
116+
"type": "array",
117+
"items": {
118+
"$ref": "#/components/schemas/Server-export"
119+
}
120+
}
121+
}
122+
}
123+
},
124+
"403": {
125+
"description": "Forbidden",
126+
"content": {
127+
"application/ld+json": {
128+
"schema": {
129+
"$ref": "#/components/schemas/Error.jsonld"
130+
}
131+
},
132+
"application/problem+json": {
133+
"schema": {
134+
"$ref": "#/components/schemas/Error"
135+
}
136+
},
137+
"application/json": {
138+
"schema": {
139+
"$ref": "#/components/schemas/Error"
140+
}
141+
}
142+
},
143+
"links": {}
144+
}
145+
},
146+
"summary": "Retrieves the collection of Server resources.",
147+
"description": "Retrieves the collection of Server resources.",
148+
"parameters": [
149+
{
150+
"name": "page",
151+
"in": "query",
152+
"description": "The collection page number",
153+
"required": false,
154+
"deprecated": false,
155+
"schema": {
156+
"type": "integer",
157+
"default": 1
158+
},
159+
"style": "form",
160+
"explode": true
161+
}
162+
]
163+
}
164+
},
165+
"/api/sites": {
166+
"get": {
167+
"operationId": "api_sites_get_collection",
168+
"tags": [
169+
"Site"
170+
],
171+
"responses": {
172+
"200": {
173+
"description": "Site collection",
174+
"content": {
175+
"application/json": {
176+
"schema": {
177+
"type": "array",
178+
"items": {
179+
"$ref": "#/components/schemas/Site-export"
180+
}
181+
}
182+
},
183+
"application/ld+json": {
184+
"schema": {
185+
"type": "array",
186+
"items": {
187+
"$ref": "#/components/schemas/Site-export"
188+
}
189+
}
190+
}
191+
}
192+
},
193+
"403": {
194+
"description": "Forbidden",
195+
"content": {
196+
"application/ld+json": {
197+
"schema": {
198+
"$ref": "#/components/schemas/Error.jsonld"
199+
}
200+
},
201+
"application/problem+json": {
202+
"schema": {
203+
"$ref": "#/components/schemas/Error"
204+
}
205+
},
206+
"application/json": {
207+
"schema": {
208+
"$ref": "#/components/schemas/Error"
209+
}
210+
}
211+
},
212+
"links": {}
213+
}
214+
},
215+
"summary": "Retrieves the collection of Site resources.",
216+
"description": "Retrieves the collection of Site resources.",
217+
"parameters": [
218+
{
219+
"name": "page",
220+
"in": "query",
221+
"description": "The collection page number",
222+
"required": false,
223+
"deprecated": false,
224+
"schema": {
225+
"type": "integer",
226+
"default": 1
227+
},
228+
"style": "form",
229+
"explode": true
230+
}
231+
]
232+
}
95233
}
96234
},
97235
"components": {
@@ -353,6 +491,43 @@
353491
]
354492
}
355493
}
494+
},
495+
"Server-export": {
496+
"type": "object",
497+
"properties": {
498+
"Name": {
499+
"default": "",
500+
"type": "string"
501+
}
502+
}
503+
},
504+
"Site-export": {
505+
"type": "object",
506+
"required": [
507+
"PHP version"
508+
],
509+
"properties": {
510+
"PHP version": {
511+
"minLength": 1,
512+
"maxLength": 10,
513+
"default": "",
514+
"type": "string"
515+
},
516+
"Primary domain": {
517+
"readOnly": true,
518+
"type": "string"
519+
},
520+
"Type": {
521+
"default": "",
522+
"type": "string"
523+
},
524+
"Server": {
525+
"$ref": "#/components/schemas/Server-export"
526+
},
527+
"rootDir": {
528+
"type": "string"
529+
}
530+
}
356531
}
357532
},
358533
"responses": {},
@@ -378,6 +553,14 @@
378553
{
379554
"name": "DetectionResult",
380555
"description": "Resource 'DetectionResult' operations."
556+
},
557+
{
558+
"name": "Server",
559+
"description": "Resource 'Server' operations."
560+
},
561+
{
562+
"name": "Site",
563+
"description": "Resource 'Site' operations."
381564
}
382565
],
383566
"webhooks": {}

0 commit comments

Comments
 (0)