...
 
Commits (11)
......@@ -2,3 +2,4 @@
venv*/
.coverage
htmlcov/
config.json
......@@ -23,7 +23,7 @@ Create `/opt/csapi` directory:
sudo mkdir -p /opt/csapi
```
And copy files `member.py`, `server.py`, and `requirements.txt` into `/opt/csapi` directory.
And copy files `csapi.py`, `server.py`, and `requirements.txt` into `/opt/csapi` directory.
You will need to install support for python venv:
```bash
......@@ -38,6 +38,8 @@ source venv/bin/activate
pip install -r requirements.txt
```
Create configuration file `/opt/csapi/config.json` based on example configuration `example-config.json`. You need to either set parameter "allow_all" to "true" to disable client certificate check or specify list of trusted Client DN's. Disabled check means that all certificates trusted by Nginx would be allowed.
### Systemd configuration
Add service description `systemd/csapi.service` to `/lib/systemd/system/csapi.service`. Then start and enable automatic startup:
......@@ -93,9 +95,10 @@ Email Address []:
Copy client.crt to Central Server machine: `/etc/nginx/csapi/client.crt`
For testing copy nginx `csapi.crt` to client and issue curl command:
For testing copy nginx `csapi.crt` to client and issue curl commands:
```bash
curl --cert client.crt --key client.key --cacert csapi.crt -i -d '{"member_code": "XX000003", "member_name": "XX Test 3", "member_class": "GOVXXX"}' -X POST https://central-server.domain.local:5443/member
curl --cert client.crt --key client.key --cacert csapi.crt -i -d '{"member_class": "GOVXXX", "member_code": "XX000003", "member_name": "XX Test 3"}' -X POST https://central-server.domain.local:5443/member
curl --cert client.crt --key client.key --cacert csapi.crt -i -d '{"member_class": "GOVXXX", "member_code": "XX000003", "subsystem_code": "SystemXX"}' -X POST https://central-server.domain.local:5443/subsystem
```
Note that you can allow multiple clients (or nodes) by creating certificate bundle. That can be done by concatenating multiple client certificates into single `client.crt` file.
......@@ -112,7 +115,7 @@ python -m unittest
Or alternatively run the test file directly:
```bash
python test_member.py
python test_csapi.py
```
In order to measure code coverage install `coverage` module:
......@@ -122,14 +125,14 @@ pip install coverage
Then run coverage analyse:
```bash
coverage run test_member.py
coverage report member.py
coverage run test_csapi.py
coverage report csapi.py
```
Alternatively you can generate html report with:
```bash
coverage run test_member.py
coverage html member.py
coverage run test_csapi.py
coverage html csapi.py
```
In order to lint the code install `pylint` module:
......@@ -139,5 +142,5 @@ pip install pylint
Then run the analyse:
```bash
pylint member.py
pylint csapi.py
```
This diff is collapsed.
{
"allow_all": false,
"allowed": [
"OU=xtss,O=RIA,C=EE"
]
}
......@@ -19,6 +19,7 @@ server {
if ($ssl_client_verify != SUCCESS) {
return 403;
}
proxy_set_header X-SSL-Client-S-DN $ssl_client_s_dn;
proxy_pass http://unix:/opt/csapi/socket/csapi.sock;
}
}
......@@ -25,34 +25,44 @@ paths:
content:
application/json:
schema:
$ref: '#/components/schemas/Response201'
$ref: '#/components/schemas/ResponseMember201'
examples:
created:
summary: Member created
value: {"code": "CREATED", "msg": "New member added"}
value: {"code": "CREATED", "msg": "New Member added"}
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/Response400'
$ref: '#/components/schemas/ResponseMember400'
examples:
missingParam:
summary: Required parameter is mussing
summary: Required parameter is missing
value: {"code": "MISSING_PARAMETER", "msg": "Request parameter member_name is missing"}
invalidClass:
summary: Member class is not found in Central Server
value: {"code": "INVALID_MEMBER_CLASS", "msg": "Provided Member Class does not exist"}
'409':
description: An existing member already exists
description: Provided Member already exists
content:
application/json:
schema:
$ref: '#/components/schemas/Response409'
$ref: '#/components/schemas/ResponseMember409'
examples:
memberExists:
summary: Provided Member already exists in Central Server
value: {"code": "MEMBER_EXISTS", "msg": "Provided Member already exists"}
'403':
description: Client certificate is not allowed
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseMember403'
examples:
memberExists:
summary: Client certificate is not allowed
value: {"code": "FORBIDDEN", "msg": "Client certificate is not allowed"}
'500':
description: Server side error
content:
......@@ -73,28 +83,132 @@ paths:
$ref: '#/components/schemas/Member'
examples:
member:
summary: A bar example
value: {"member_code": "00000000", "member_name": "Member 0", "member_class": "GOV"}
summary: Example request parameters
value: {"member_class": "GOV", "member_code": "00000000", "member_name": "Member 0"}
description: New Member to add
/subsystem:
post:
tags:
- admin
summary: add new X-Road Subsystem
operationId: addSubsystem
description: Adds new X-Road Subsystem to Central Server
responses:
'201':
description: Subsystem added
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseSubsystem201'
examples:
created:
summary: Subsystem created
value: {"code": "CREATED", "msg": "New Subsystem added"}
'400':
description: Invalid input
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseSubsystem400'
examples:
missingParam:
summary: Required parameter is mussing
value: {"code": "MISSING_PARAMETER", "msg": "Request parameter member_name is missing"}
invalidClass:
summary: Member class is not found in Central Server
value: {"code": "INVALID_MEMBER_CLASS", "msg": "Provided Member Class does not exist"}
ivalidMember:
summary: Member class is not found in Central Server
value: {"code": "INVALID_MEMBER", "msg": "Provided Member does not exist"}
'403':
description: Client certificate is not allowed
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseSubsystem403'
examples:
memberExists:
summary: Client certificate is not allowed
value: {"code": "FORBIDDEN", "msg": "Client certificate is not allowed"}
'409':
description: Provided Subsystem already exists
content:
application/json:
schema:
$ref: '#/components/schemas/ResponseSubsystem409'
examples:
memberExists:
summary: Provided Subsystem already exists in Central Server
value: {"code": "SUBSYSTEM_EXISTS", "msg": "Provided Subsystem already exists"}
'500':
description: Server side error
content:
application/json:
schema:
$ref: '#/components/schemas/Response500'
examples:
dbConfError:
summary: Application cannot read or parse database configuration
value: {"code": "DB_CONF_ERROR", "msg": "Cannot access database configuration"}
dbError:
summary: A generic unclassified DB error occured
value: {"code": "DB_ERROR", "msg": "Unclassified database error"}
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/Subsystem'
examples:
member:
summary: Example request parameters
value: {"member_class": "GOV", "member_code": "00000000", "subsystem_code": "Subsystem0"}
description: New Subsystem to add
components:
schemas:
Member:
type: object
required:
- member_class
- member_code
- member_name
- member_class
properties:
member_class:
type: string
example: GOV
member_code:
type: string
example: 00000000
member_name:
type: string
example: Member 0
Subsystem:
type: object
required:
- member_class
- member_code
- subsystem_code
properties:
member_class:
type: string
example: GOV
Response201:
member_code:
type: string
example: 00000000
subsystem_code:
type: string
example: Subsystem0
ResponseMember201:
type: object
properties:
code:
type: string
enum:
- CREATED
example: CREATED
msg:
type: string
example: New Member added
ResponseSubsystem201:
type: object
properties:
code:
......@@ -104,8 +218,8 @@ components:
example: CREATED
msg:
type: string
example: New member added
Response400:
example: New Subsystem added
ResponseMember400:
type: object
properties:
code:
......@@ -117,7 +231,42 @@ components:
msg:
type: string
example: Request parameter member_name is missing
Response409:
ResponseSubsystem400:
type: object
properties:
code:
type: string
enum:
- MISSING_PARAMETER
- INVALID_MEMBER_CLASS
- INVALID_MEMBER
example: MISSING_PARAMETER
msg:
type: string
example: Request parameter subsystem_code is missing
ResponseMember403:
type: object
properties:
code:
type: string
enum:
- FORBIDDEN
example: FORBIDDEN
msg:
type: string
example: Client certificate is not allowed
ResponseSubsystem403:
type: object
properties:
code:
type: string
enum:
- FORBIDDEN
example: FORBIDDEN
msg:
type: string
example: Client certificate is not allowed
ResponseMember409:
type: object
properties:
code:
......@@ -128,6 +277,17 @@ components:
msg:
type: string
example: Provided Member already exists
ResponseSubsystem409:
type: object
properties:
code:
type: string
enum:
- SUBSYSTEM_EXISTS
example: SUBSYSTEM_EXISTS
msg:
type: string
example: Provided Subsystem already exists
Response500:
type: object
properties:
......
......@@ -3,13 +3,13 @@
import logging
from flask import Flask
from flask_restful import Api
from member import MemberApi
from csapi import MemberApi, SubsystemApi, load_config
handler = logging.FileHandler('/var/log/xroad/csapi.log')
handler.setFormatter(logging.Formatter('%(asctime)s - %(process)d - %(levelname)s: %(message)s'))
# Member module logger
logger_m = logging.getLogger('member')
# CS API module logger
logger_m = logging.getLogger('csapi')
logger_m.setLevel(logging.INFO)
logger_m.addHandler(handler)
......@@ -18,8 +18,11 @@ logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.addHandler(handler)
config = load_config('config.json')
app = Flask(__name__)
api = Api(app)
api.add_resource(MemberApi, '/member')
api.add_resource(MemberApi, '/member', resource_class_kwargs={'config': config})
api.add_resource(SubsystemApi, '/subsystem', resource_class_kwargs={'config': config})
logger.info('Starting Central Server API')
This diff is collapsed.
This diff is collapsed.