Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

POC hybrid vp token #66

Open
wants to merge 30 commits into
base: ebsi-verify-conformance
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
29ad4b2
Merge pull request #63 from malach-it/ebsi-verify-conformance
patatoid Oct 17, 2024
195ca88
Bump rollup and vite in /apps/boruta_admin/assets
dependabot[bot] Oct 17, 2024
8a4f230
bump to 0.5.0
patatoid Oct 17, 2024
ffe13f9
[identity] fix federated users deletion
patatoid Oct 17, 2024
5a1a1fa
[doc] add ebsi verify certification badge
patatoid Oct 21, 2024
b333820
[admin] client key pair type configuration
patatoid Oct 21, 2024
b5abe93
[infra] fix linter warning
patatoid Oct 21, 2024
df82e0a
[admin] organization creation in static configuration
patatoid Oct 22, 2024
3162e83
[doc] reorganize certification marks
patatoid Oct 22, 2024
7fba9a8
[auth] display status in claims configuration
patatoid Oct 24, 2024
bc197b0
[doc] add oid4vp reference in readme
patatoid Oct 29, 2024
4766bdd
[admin] ability import users with metadata
patatoid Oct 29, 2024
dbc1917
[identity] wrap internal user creation in a transaction
patatoid Oct 29, 2024
c0767cd
Merge pull request #68 from malach-it/dependabot/npm_and_yarn/apps/bo…
patatoid Nov 8, 2024
875e0d8
[admin] fix user import with hashed password
patatoid Nov 17, 2024
fb08680
[identity] fix resource owner extra claims display
patatoid Nov 17, 2024
3a05f8e
[infra] fix flaky tests
patatoid Nov 17, 2024
bdb910c
[infra] remove dialyzer from ci
patatoid Nov 17, 2024
0605b09
Revert "Merge pull request #68 from malach-it/dependabot/npm_and_yarn…
patatoid Nov 17, 2024
254c8b4
[identity] fix user metadata edition
patatoid Nov 17, 2024
8a778a6
[admin] fix user empty metadata save
patatoid Nov 21, 2024
f27a9a3
bump to 0.5.1
patatoid Nov 21, 2024
5fcfd7f
[ssi] presentation hybrid flow
patatoid Sep 19, 2024
0996395
[infra] remove gettext + fix mix lock and mime
patatoid Sep 19, 2024
4c85c0b
[ssi] store user session on presentation submission
patatoid Sep 22, 2024
ab14ca8
[ssi] fix direct post handler
patatoid Oct 13, 2024
6058192
[identity] fix wallet user deletion
patatoid Oct 17, 2024
ed4a2c7
remove documentation link
patatoid Oct 18, 2024
67b4122
[ssi] client_id as sub for anonymous resource owners
patatoid Nov 21, 2024
9eaed85
[auth] update boruta dependency (fix anonymous resource owners)
patatoid Nov 22, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on:
push:
branches:
- ebsi-verify-conformance
- poc-hybrid-vp-token
workflow_run:
workflows:
- Continuous Integration
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ jobs:
- name: Run Credo
run: mix credo --strict

- name: Run Dialyzer
run: mix dialyzer
# - name: Run Dialyzer
# run: mix dialyzer

unit_tests:
name: Unit Tests
Expand Down
28 changes: 25 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,43 @@

> Note that 0.X.X releases are reverved for the beta version of the server and may include breaking changes.

## [0.5.1] - 2024-11-21

### Added

- [admin] user csv import metadata
- [infra] organization creation in static configuration
- [admin] client key pair configuration + support for EC keys

### Fixed

- [ssi] several verifiable credentials issuance and presentation fixes
- [auth] configurable status display in id_token claims
- [admin] user with empty metadata save
- [admin] federated users deletion


## [0.5.0] - 2024-10-17

### Added

- [ssi] OpenID for Verifiable Credentials Presentation implementation

## [0.4.2] - 2024-09-20

### Fixed

- fix authorize entrypoint
- [auth] fix authorize entrypoint

## [0.4.1] - 2024-09-18

### Fixed

- ipv6 log display
- [admin] ipv6 log display

### Security

- remove .env.example.sig as suspicious file
- [infra] remove .env.example.sig as suspicious file

## [0.4.0] 2024-09-01

Expand Down
15 changes: 5 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,6 @@ Boruta is a standalone authorization server implementing OAuth 2.0 and Openid Co

This server is on an ongoing beta stage. Developments are moving fast on master then are keen to be less stable. Tagged versions are said to be more stable and sanity tested.

## Documentation

The documentation of boruta server is available [here](https://boruta-developers.malach.it/docs/intro) it provides insights about its usage.

## Implemented specifications and certification

As it, boruta server aim to follow the RFCs from IETF:
Expand All @@ -27,25 +23,24 @@ And the specifications from the OpenID Foundation:
- [OpenID Connect Dynamic Client Registration 1.0 incorporating errata set 1](https://openid.net/specs/openid-connect-registration-1_0.html)
- [OpenID for Verifiable Credential Issuance](https://openid.net/specs/openid-4-verifiable-credential-issuance-1_0.html)
- [Self-Issued OpenID Provider v2](https://openid.net/specs/openid-connect-self-issued-v2-1_0.html)
- [OpenID for Verifiable Presentations - draft 21](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html)

This server has been certified for the Basic, Implicit, and Hybrid OpenID Provider profiles by the OpenID Foundation on October, 18th 2022 for the tagged version 0.1.0

This server has been certified for the Config and Dynamic OpenID Provider profiles by the OpenID Foundation on May, 16th 2023 for the tagged version 0.2.0

![OpenID certified](https://github.com/malach-it/boruta-server/blob/master/images/oid-certification-mark.png?raw=true)

This server has also been certified against the [European Blockchain Service Infrastructure (EBSI)](https://ec.europa.eu/digital-building-blocks/sites/display/EBSI) issuance test suite for the tagged version 0.4.0.
This server has also been certified against the [European Blockchain Service Infrastructure (EBSI)](https://ec.europa.eu/digital-building-blocks/sites/display/EBSI) issuance test suite for the tagged version 0.4.0 and for verifiable credential verification for the tagged version 0.5.0.

![EBSI certified](https://github.com/malach-it/boruta-server/blob/master/images/ebsi-certification-issuance.png?raw=true)
![EBSI certified - issue](https://github.com/malach-it/boruta-server/blob/master/images/ebsi-certification-issuance.png?raw=true)
![EBSI certified - verify](https://github.com/malach-it/boruta-server/blob/master/images/ebsi-certification-verify.png?raw=true)
![OpenID certified](https://github.com/malach-it/boruta-server/blob/master/images/oid-certification-mark.png?raw=true)

## Installation

A [loom presentation](https://www.loom.com/share/77006360fdac44bc9113fab9cf30aba5) about how to get a server up and running.

Note that the easiest way to try the server is by using docker compose.

> During the installation, an optional prompt will ask for statistical info, it would be great if you could fill them.

### System wide setup (Debian based)

You can perform a system wide installation performing the following command. It will create a systemd service to run the server. During the installation, you will be asked to fill out the environment variables for the server. The environment takes `.env.example` as a basis.
Expand Down
18 changes: 18 additions & 0 deletions apps/boruta_admin/assets/src/components/Forms/ClientForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,23 @@
</div>
</div>
<div ref="security" data-tab="security" class="ui bottom attached tab segment">
<h3>Key type</h3>
<div class="field" :class="{ 'error': client.errors?.key_pair_type }">
<select v-model="client.key_pair_type.type">
<option v-for="keyPairType in Object.keys(keyPairTypes)" :value="keyPairType" :key="keyPairType">
{{ keyPairType }}
</option>
</select>
</div>
<div v-for="(value, param) in keyPairTypes[client.key_pair_type.type]" class="field" :class="{ 'error': client.errors?.key_pair_type }">
<label>{{ param }}</label>
<select v-if="value instanceof Array" v-model="client.key_pair_type[param]">
<option v-for="option in value" :value="option" :key="option">
{{ option }}
</option>
</select>
<input v-else type="text" v-model="client.key_pair_type[param]" />
</div>
<h3>Token signatures</h3>
<div class="ui segment">
<div class="inline fields" :class="{ 'error': client.errors?.id_token_signature_alg }">
Expand Down Expand Up @@ -220,6 +237,7 @@ export default {
},
data() {
return {
keyPairTypes: Client.keyPairTypes,
keyPairs: [],
idTokenSignatureAlgorithms: Client.idTokenSignatureAlgorithms,
UserinfoResponseSignatureAlgorithms: Client.UserinfoResponseSignatureAlgorithms,
Expand Down
19 changes: 17 additions & 2 deletions apps/boruta_admin/assets/src/components/Forms/UserForm.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
</div>
<section v-if="user.backend.metadata_fields.length">
<h3>Metadata</h3>
<div class="ui segment" v-for="field in user.backend.metadata_fields">
<div class="ui metadata segment" v-for="field in user.backend.metadata_fields">
<h4>{{ field.attribute_name }}</h4>
<div class="ui two column stackable grid">
<div class="ui three column stackable grid">
<div class="column">
<div class="field" :class="{ 'error': user.errors?.metadata }">
<label>Value</label>
Expand All @@ -47,6 +47,15 @@
</select>
</div>
</div>
<div class="column">
<div class="field">
<label>Claim format</label>
<div class="ui toggle checkbox">
<input type="checkbox" v-model="user.metadata[field.attribute_name].displayStatus">
<label>display status</label>
</div>
</div>
</div>
</div>
</div>
</section>
Expand Down Expand Up @@ -172,3 +181,9 @@ export default {
}
}
</script>

<style lang="scss">
.metadata .toggle {
padding: 8px;
}
</style>
20 changes: 20 additions & 0 deletions apps/boruta_admin/assets/src/models/client.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,15 @@ const allGrantTypes = [
'introspect'
]

const keyPairTypes = {
'ec': { curve: ['P-256', 'P-384', 'P-512'] },
'rsa': { modulus_size: '1024', exponent_size: '65537' }
}

const defaults = {
errors: null,
key_pair_id: null,
key_pair_type: { type: 'rsa', modulus_size: '1024', exponent_size: '65537' },
authorize_scopes: false,
authorized_scopes: [],
redirect_uris: [],
Expand All @@ -40,6 +46,7 @@ const assign = {
confidential: function ({ confidential }) { this.confidential = confidential },
pkce: function ({ pkce }) { this.pkce = pkce },
public_key: function ({ public_key }) { this.public_key = public_key },
key_pair_type: function ({ key_pair_type }) { this.key_pair_type = key_pair_type },
did: function ({ did }) { this.did = did },
access_token_ttl: function ({ access_token_ttl }) { this.access_token_ttl = access_token_ttl },
authorization_code_ttl: function ({ authorization_code_ttl }) { this.authorization_code_ttl = authorization_code_ttl },
Expand Down Expand Up @@ -217,6 +224,7 @@ class Client {
token_endpoint_auth_methods,
jwt_public_key,
key_pair_id,
key_pair_type,
response_mode
} = this

Expand Down Expand Up @@ -247,11 +255,14 @@ class Client {
token_endpoint_auth_methods,
jwt_public_key,
key_pair_id,
key_pair_type,
response_mode
}
}
}

Client.keyPairTypes = keyPairTypes

Client.api = function () {
const accessToken = localStorage.getItem('access_token')

Expand Down Expand Up @@ -280,6 +291,9 @@ Client.get = function (id) {
}

Client.idTokenSignatureAlgorithms = [
"ES256",
"ES384",
"ES512",
"HS256",
"HS384",
"HS512",
Expand All @@ -289,6 +303,9 @@ Client.idTokenSignatureAlgorithms = [
]

Client.clientJwtAuthenticationSignatureAlgorithms = [
"ES256",
"ES384",
"ES512",
"HS256",
"HS384",
"HS512",
Expand All @@ -299,6 +316,9 @@ Client.clientJwtAuthenticationSignatureAlgorithms = [

Client.UserinfoResponseSignatureAlgorithms = [
null,
"ES256",
"ES384",
"ES512",
"HS256",
"HS384",
"HS512",
Expand Down
30 changes: 28 additions & 2 deletions apps/boruta_admin/assets/src/models/user.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,17 @@ const assign = {
email: function ({ email }) { this.email = email },
totp_registered_at: function ({ totp_registered_at }) { this.totp_registered_at = totp_registered_at },
federated_metadata: function ({ federated_metadata }) { this.federated_metadata = federated_metadata },
metadata: function ({ metadata }) { this.metadata = metadata },
metadata: function ({ metadata: rawMetadata }) {
const metadata = {}

for (const key in rawMetadata) {
metadata[key] = {
displayStatus: rawMetadata[key].display?.includes('status'),
...rawMetadata[key]
}
}
this.metadata = metadata
},
group: function ({ group }) { this.group = group },
authorized_scopes: function ({ authorized_scopes }) {
this.authorized_scopes = authorized_scopes.map((scope) => {
Expand Down Expand Up @@ -109,7 +119,19 @@ class User {
}

get serialized () {
const { id, email, password, metadata, group, authorized_scopes, roles, organizations } = this
const { id, email, password, metadata: rawMetadata, group, authorized_scopes, roles, organizations } = this

const metadata = {}

for (const key in rawMetadata) {
if (rawMetadata[key]?.value) {
metadata[key] = {
display: rawMetadata[key].displayStatus ? ['status'] : [],
value: rawMetadata[key].value,
status: rawMetadata[key].status
}
}
}

return {
id,
Expand Down Expand Up @@ -169,6 +191,10 @@ User.upload = function ({ backendId, file, options }) {
if (options.hashPassword && options.hashPassword !== '')
formData.append("options[hash_password]", options.hashPassword)

options.metadataHeaders.forEach(header => {
formData.append("options[metadata_headers][]", `${header.origin}>${header.target}`)
})

return this.api().post('/', formData, {
headers: {
'Content-Type': 'multipart/form-data'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
</div>
</div>
</div>
<router-link :to="{ name: 'client-list' }" class="ui right floated button">Back</router-link>
<router-link :to="{ name: 'user-list' }" class="ui right floated button">Back</router-link>
</div>
</div>
<div class="twelve wide column">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@
<div class="ui segment">
<FormErrors :errors="importErrors" v-if="importErrors" />
<form class="ui form" @submit.prevent="upload()">
<div class="field">
<label>Backend</label>
<select v-model="backendId">
<option :value="backend.id" v-for="backend in backends" :key="backend.id">{{ backend.name }}</option>
</select>
</div>
<h3>Base fields</h3>
<div class="field">
<label>username header</label>
<input type="text" v-model="options.usernameHeader" placeholder="username" />
Expand All @@ -24,6 +19,27 @@
<label>Hash password</label>
</div>
</div>
<h3>Metadata fields</h3>
<div class="field">
<div v-for="header in options.metadataHeaders" class="metadata-header">
<div class="field">
<label>metadata header</label>
<input type="text" v-model="header.origin" placeholder="origin" />
</div>
<div class="field">
<label>metadata field</label>
<input type="text" v-model="header.target" placeholder="target" />
</div>
<hr />
</div>
<a class="ui blue fluid button" @click="addMetadataHeader()">Add metadataHeader</a>
</div>
<div class="field">
<label>Backend</label>
<select v-model="backendId">
<option :value="backend.id" v-for="backend in backends" :key="backend.id">{{ backend.name }}</option>
</select>
</div>
<div class="field">
<label>CSV file</label>
<input type="file" @change="setFile" accept=".csv" :key="fileUpdates" />
Expand Down Expand Up @@ -83,7 +99,7 @@ export default {
return {
fileUpdates: 0,
file: null,
options: {},
options: {metadataHeaders: []},
backends: [],
backendId: null,
pending: false,
Expand All @@ -100,6 +116,9 @@ export default {
setFile (event) {
this.file = event.target.files[0]
},
addMetadataHeader () {
this.options.metadataHeaders.push({})
},
upload () {
const { backendId, file, options } = this

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,10 @@ export default {
this.errorMessage = false
this.deleted = false
user.destroy().then(() => {
this.getUsers(this.currentPage, this.userQuery)
this.deleted = true
this.getUsers(this.currentPage, this.userQuery).then(() => {
this.deleted = false
})
}).catch((error) => {
this.errorMessage = error.response.data.message
})
Expand Down
Loading
Loading