-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #64 from ConductionNL/development
Development to main
- Loading branch information
Showing
55 changed files
with
2,479 additions
and
296 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
name: Main Branch Protection | ||
|
||
on: | ||
pull_request: | ||
branches: | ||
- main | ||
|
||
jobs: | ||
check-branch: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Check branch | ||
run: | | ||
if [[ ${GITHUB_HEAD_REF} != development ]] && [[ ${GITHUB_HEAD_REF} != documentation ]] && ! [[ ${GITHUB_HEAD_REF} =~ ^hotfix/ ]]; | ||
then | ||
echo "Error: Pull request must come from 'development', 'documentation' or 'hotfix/' branch" | ||
exit 1 | ||
fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
name: Lint Check | ||
|
||
on: | ||
pull_request: | ||
branches: | ||
- development | ||
- main | ||
|
||
jobs: | ||
lint-check: | ||
runs-on: ubuntu-latest | ||
|
||
steps: | ||
- name: Checkout repository | ||
uses: actions/checkout@v2 | ||
|
||
- name: Install dependencies | ||
run: npm i | ||
|
||
- name: Linting | ||
run: npm run lint |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
# OpenConector | ||
|
||
Provides gateway and service bus functionality like mapping, translation and synchronisation of data | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
# Authentication on sources | ||
|
||
In order to authenticate on other sources there are possibilities based upon the way the source expects autentication parameters. | ||
These parameters can be set in the source configuration. For example, if the source expects an API key in the headers, we can set the parameter `headers.Authorization` with the API key as value. | ||
|
||
Usually, sources tend to use dynamic authorization parameters in order to prevent the same authentication parameter from being used by adversaries that catch a call and deduce the parameter. | ||
|
||
At the moment, OpenConnector supports two dynamic authentication methods, OAuth and JWT Bearers. | ||
|
||
## OAuth | ||
|
||
To use OAuth we put in our Authorization header the following value: | ||
```twig | ||
Bearer {{ oauthToken(source) }} | ||
``` | ||
This will impose an OAuth 2.0 access token after `Bearer` if the field `authenticationConfig` contains correct values. | ||
OpenConnector supports the OAuth 2.0 protocol with client credentials and password credentials as grant_types. | ||
|
||
>[!NOTE] | ||
> TODO: How to add authenticationConfig parameters in frontend | ||
When using OAuth, OpenConnector supports the following parameters: | ||
|
||
### Standard parameters | ||
* `grant_type`: The type of grant we have to use at the source. Supported are `client_credentials` and `password` | ||
* `scope`: The scope(s) needed to perform the requests we want to do in the API. | ||
* `tokenUrl`: The URL used to fetch the actual access token. Usually this url can be recognised by its path ending on `/oauth/token` | ||
* `authentication`: Location of the credentials, either `body` for credentials included in the request body, or `basic_auth` when the credentials have to be sent as a basic_auth header. | ||
> Only used when `grant_type` is `client_credentials` | ||
* `client_id`: The client id of the OAuth client | ||
> Only used when `grant_type` is `client_credentials` | ||
* `client_secret`: The secret for the OAuth client | ||
> Only used when `grant_type` is `client_credentials` | ||
* `username`: The username for the OAuth client | ||
> Only used when `grant_type` is `password` | ||
* `password`: The password for the OAuth client | ||
> Only used when `grant_type` is `password` | ||
This results in the following example: | ||
```json | ||
{ | ||
"grant_type": "client_credentials", | ||
"scope": "api", | ||
"authentication": "body", | ||
"tokenUrl": "https://example.com/oauth/token", | ||
"client_id": "test-client", | ||
"client_secret": "some secret value" | ||
} | ||
``` | ||
### Custom parameters | ||
|
||
> [!WARNING] | ||
> Custom parameters are currently in beta, it is not recommended to use them in production environments. | ||
At the moment, OpenConnector is tested with the following custom parameters: | ||
|
||
* `client_assertion_type`, only meaningful at the moment when value is set to `urn:ietf:params:oauth:client-assertion-type:jwt-bearer`. When this is set (for Microsoft authentications) the following fields are needed to generate the `client-assertion`-field | ||
- `private_key`: The base64 encoded private key of the certificate uploaded to Microsoft. | ||
- `x5t`: The base64 encoded sha1 fingerprint of the uploaded certificate, generated by running the following command: | ||
|
||
```bash | ||
echo $(openssl x509 -in certificate.crt -fingerprint -noout) | sed 's/SHA1 Fingerprint=//g' | sed 's/://g' | xxd -r -ps | base64`) | ||
``` | ||
|
||
- `payload`: The payload of the JWT generated as `client_assertion`, this can contain Twig variables to render, for example to set timestamps in the JWT payload. | ||
|
||
## JWT Bearer | ||
|
||
A second supported way of using dynamic authentication is setting a JWT Bearer. This means setting a header or query parameter with a JWT token. | ||
|
||
This can for example be used by setting an Authorization header with the following value: | ||
```twig | ||
Bearer {{ jwtToken(source) }} | ||
``` | ||
|
||
This will impose a JWT token after the bearer. For this, the `authenticationConfig` field of the source needs to contain the following fields: | ||
* `algorithm`: The algorithm that should be used to generate the JWT. Supported are `HS256`, `HS384` and `HS512` for HMAC algorithms, `RS256`, `RS384`, `RS512` and `PS256` for RSA algorithms. | ||
* `secret`: The secret used for the JWT. This can either be a HMAC shared secret, or a RSA private key in base64 encoding. | ||
* `payload`: The payload of your JWT, json_encoded. | ||
|
||
This results in the following example for the `authenticationConfig` parameter in i.e. an OpenZaak source. | ||
```json | ||
{ | ||
"algorithm": "HS256", | ||
"secret": "YOUR_256BIT_(32BYTE)_HMAC_SECRET", | ||
"payload": "{\"iss\":\"my_zgw_client\",\"iat\":{{ 'now'|date('U') }},\"client_id\":\"my_zgw_client\",\"user_id\":\"my_zgw_client\",\"user_representation\":\"[email protected]\",\"aud\":\"my_zgw_client\"}" | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,8 @@ | |
use OCP\IAppConfig; | ||
use OCP\IRequest; | ||
use OCP\IURLGenerator; | ||
use Psr\Container\ContainerExceptionInterface; | ||
use Psr\Container\NotFoundExceptionInterface; | ||
|
||
class MappingsController extends Controller | ||
{ | ||
|
@@ -31,7 +33,8 @@ public function __construct( | |
IRequest $request, | ||
private readonly IAppConfig $config, | ||
private readonly MappingMapper $mappingMapper, | ||
private readonly MappingService $mappingService | ||
private readonly MappingService $mappingService, | ||
private readonly ObjectService $objectService | ||
) | ||
{ | ||
parent::__construct($appName, $request); | ||
|
@@ -125,17 +128,17 @@ public function create(): JSONResponse | |
return new JSONResponse($this->mappingMapper->createFromArray(object: $data)); | ||
} | ||
|
||
/** | ||
* Updates an existing mapping | ||
* | ||
* This method updates an existing mapping based on its ID. | ||
* | ||
* @NoAdminRequired | ||
* @NoCSRFRequired | ||
* | ||
* @param string $id The ID of the mapping to update | ||
* @return JSONResponse A JSON response containing the updated mapping details | ||
*/ | ||
/** | ||
* Updates an existing mapping | ||
* | ||
* This method updates an existing mapping based on its ID. | ||
* | ||
* @NoAdminRequired | ||
* @NoCSRFRequired | ||
* | ||
* @param int $id The ID of the mapping to update | ||
* @return JSONResponse A JSON response containing the updated mapping details | ||
*/ | ||
public function update(int $id): JSONResponse | ||
{ | ||
$data = $this->request->getParams(); | ||
|
@@ -151,60 +154,66 @@ public function update(int $id): JSONResponse | |
return new JSONResponse($this->mappingMapper->updateFromArray(id: (int) $id, object: $data)); | ||
} | ||
|
||
/** | ||
* Deletes a mapping | ||
* | ||
* This method deletes a mapping based on its ID. | ||
* | ||
* @NoAdminRequired | ||
* @NoCSRFRequired | ||
* | ||
* @param string $id The ID of the mapping to delete | ||
* @return JSONResponse An empty JSON response | ||
*/ | ||
/** | ||
* Deletes a mapping | ||
* | ||
* This method deletes a mapping based on its ID. | ||
* | ||
* @NoAdminRequired | ||
* @NoCSRFRequired | ||
* | ||
* @param int $id The ID of the mapping to delete | ||
* @return JSONResponse An empty JSON response | ||
* @throws \OCP\DB\Exception | ||
*/ | ||
public function destroy(int $id): JSONResponse | ||
{ | ||
$this->mappingMapper->delete($this->mappingMapper->find((int) $id)); | ||
|
||
return new JSONResponse([]); | ||
} | ||
|
||
/** | ||
* Tests a mapping | ||
* | ||
* This method tests a mapping with provided input data and optional schema validation. | ||
* | ||
* @NoAdminRequired | ||
* @NoCSRFRequired | ||
* | ||
* @return JSONResponse A JSON response containing the test results | ||
* | ||
* @example | ||
* Request: | ||
* { | ||
* "inputObject": "{\"name\":\"John Doe\",\"age\":30,\"email\":\"[email protected]\"}", | ||
* "mapping": { | ||
* "mapping": { | ||
* "fullName":"{{name}}", | ||
* "userAge":"{{age}}", | ||
* "contactEmail":"{{email}}" | ||
* } | ||
* }, | ||
* "schema": "user_schema_id", | ||
* "validation": true | ||
* } | ||
* | ||
* Response: | ||
* { | ||
* "resultObject": { | ||
* "fullName": "John Doe", | ||
* "userAge": 30, | ||
* "contactEmail": "[email protected]" | ||
* }, | ||
* "isValid": true, | ||
* "validationErrors": [] | ||
* } | ||
*/ | ||
/** | ||
* Tests a mapping | ||
* | ||
* This method tests a mapping with provided input data and optional schema validation. | ||
* | ||
* @NoAdminRequired | ||
* @NoCSRFRequired | ||
* | ||
* @param ObjectService $objectService | ||
* @param IURLGenerator $urlGenerator | ||
* | ||
* @return JSONResponse A JSON response containing the test results | ||
* @throws ContainerExceptionInterface | ||
* @throws NotFoundExceptionInterface | ||
* | ||
* @example | ||
* Request: | ||
* { | ||
* "inputObject": "{\"name\":\"John Doe\",\"age\":30,\"email\":\"[email protected]\"}", | ||
* "mapping": { | ||
* "mapping": { | ||
* "fullName":"{{name}}", | ||
* "userAge":"{{age}}", | ||
* "contactEmail":"{{email}}" | ||
* } | ||
* }, | ||
* "schema": "user_schema_id", | ||
* "validation": true | ||
* } | ||
* | ||
* Response: | ||
* { | ||
* "resultObject": { | ||
* "fullName": "John Doe", | ||
* "userAge": 30, | ||
* "contactEmail": "[email protected]" | ||
* }, | ||
* "isValid": true, | ||
* "validationErrors": [] | ||
* } | ||
*/ | ||
public function test(ObjectService $objectService, IURLGenerator $urlGenerator): JSONResponse | ||
{ | ||
$openRegisters = $objectService->getOpenRegisters(); | ||
|
@@ -291,4 +300,57 @@ public function test(ObjectService $objectService, IURLGenerator $urlGenerator): | |
'validationErrors' => $validationErrors | ||
]); | ||
} | ||
|
||
/** | ||
* Saves a mapping object | ||
* | ||
* This method saves a mapping object based on POST data. | ||
* | ||
* @NoAdminRequired | ||
* @NoCSRFRequired | ||
* | ||
* @return JSONResponse|null | ||
* @throws ContainerExceptionInterface | ||
* @throws NotFoundExceptionInterface | ||
*/ | ||
public function saveObject(): ?JSONResponse | ||
{ | ||
// Check if the OpenRegister service is available | ||
$openRegisters = $this->objectService->getOpenRegisters(); | ||
if ($openRegisters !== null) { | ||
$data = $this->request->getParams(); | ||
return new JSONResponse($openRegisters->saveObject($data['register'], $data['schema'], $data['object'])); | ||
} | ||
|
||
return null; | ||
} | ||
|
||
/** | ||
* Retrieves a list of objects to map to | ||
* | ||
* This method retrieves a list of objects to map to based on GET data. | ||
* | ||
* @NoAdminRequired | ||
* @NoCSRFRequired | ||
* | ||
* @return JSONResponse | ||
* @throws ContainerExceptionInterface | ||
* @throws NotFoundExceptionInterface | ||
*/ | ||
public function getObjects(): JSONResponse | ||
{ | ||
// Check if the OpenRegister service is available | ||
$openRegisters = $this->objectService->getOpenRegisters(); | ||
$data = []; | ||
if ($openRegisters !== null) { | ||
$data['openRegisters'] = true; | ||
$data['availableRegisters'] = $openRegisters->getRegisters(); | ||
} | ||
else { | ||
$data['openRegisters'] = false; | ||
} | ||
|
||
return new JSONResponse($data); | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.