Skip to content

Commit

Permalink
Release v1.0.0 (#11)
Browse files Browse the repository at this point in the history
* Add app configs

* Add app configs

* Add app configs

* Add app configs

* Add app configs

* Implemented abstract broker for wallet

* Vault abstract

* Update application.yml

* Did generation

* DidGeneration

* Build vc

* crypto

* Tests

* Update OrionLdAdapterTest.java

* Tests

* Fix conflict

* Remove unused import

* vp

* Code Review

* update properties

* Move logic

* Refactor some clases and restructured facade

* Move logic from micros to walletServer

* test

* test

* test

* Vp

* test

* Remove unused code

* Update build.gradle

* tests

* tets

* Test

* Test

* add comments

* Documentation

* Tests

* Test

* Test

* Tests

* Refactor didService logic

---------

Co-authored-by: Oriol Canadés <oriol.canades@in2.es>
Co-authored-by: Oriol Canadés <83498869+oriolcanadesin2@users.noreply.github.com>
  • Loading branch information
3 people committed Feb 21, 2024
1 parent aeb7031 commit b5fc778
Show file tree
Hide file tree
Showing 70 changed files with 3,133 additions and 915 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased] v1.0.0
## [v1.0.0](https://github.com/in2workspace/wallet-server/releases/tag/v1.0.0) - 2024-2-19
### Added
- Implemented key pair generation using the secp256r1 algorithm.
- Generate did:key identifier from ES256 key algorithm.
- Generate did:key:jwk_jcs-pub identifier from ES256 key algorithm.
- Support Scorpio Context Broker (v.4.1.14)
- Support Orion-LD
- Support Hashicorp Vault
- Support AZ Key Vault
- Introduced EBSI-compliant flows for issuing and presenting digital credentials.
- Developed functionalities for QR content interpretation and credential offer management.
- Enabled the ability to interpret presentation submission filters for credential verification against user criteria.
- Creational Patterns, utilization of the Builder pattern
- Structural Patterns, implementation of the Facade pattern.
- Factory and Adapter Patterns: Current use of the Factory pattern combined with the Adapter pattern, enhancing the flexibility and reusability of object creation and interaction within the system.
- Type Interpretation in Presentation Definition Filters: Added the capability to interpret the type of Verifiable Credential in Presentation Definition filters, allowing for more precise selection and verification of the credentials presented by the user. This enhancement facilitates adaptation to various use cases where verifying the specific type of the user's verifiable credential is required.
80 changes: 78 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,90 @@ Wallet Server is a service that allows to manage digital credentials. It is desi
Wallet Server includes the requested features described in the [EUDI Wallet Arquitecture Reference](https://github.com/eu-digital-identity-wallet/eudi-doc-architecture-and-reference-framework/blob/main/docs/arf.md), and it is EBSI compliance ([EBSI test v3.4](https://hub.ebsi.eu/wallet-conformance)).

## Features
- Create key pair from secp256r1 algorithm.
- Create did:key identifier from ES256 key algorithm.
- Create did:key:jwk_jcs-pub identifier from ES256 key algorithm.
- Complete flows compliant with EBSI for issuing and presenting digital credentials.
- Context Broker Integration: Facilitates advanced management of credentials and DIDs through standardized interfaces.
- Vault Integration: Provides secure cryptographic storage for private keys using state-of-the-art vault technology.
- Cross-Device and Same-Device support.


## Installation
### Prerequisites
- [Docker Desktop](https://www.docker.com/)
- [Git](https://git-scm.com/)

## Supported Platforms
* Keycloak //todo version

### Context Brokers
Wallet Server supports integration with various context brokers, offering flexibility in deployment and operation:

* Scorpio //todo version
* Orion-LD //todo version
* Hashicorp Vault //todo version

### Vault Solutions
For secure storage of private keys, Wallet Server integrates with leading vault technologies:

* HashiCorp Vault //todo version
* Azure Key Vault //todo version

This integration ensures high-level security for cryptographic operations within the Wallet Server ecosystem.

## Configuration

Ensure to adjust the environment variables to match your configurations.

* Wallet-Server Configuration
```yaml
wallet-server:
image: in2kizuna/wallet-server:v1.0.0
environment:
# Logging Configuration
LOGGING_LEVEL_ES_IN2_WALLET_SERVER: "DEBUG" # Set logging level (e.g., DEBUG, INFO, WARN, ERROR)
# OpenAPI Configuration
OPENAPI_SERVER_URL: "https://yourdomain.com" # The URL where your Wallet Server is hosted
OPENAPI_SERVER_DESCRIPTION: "Wallet Server API" # Brief description of your server
OPENAPI_INFO_TITLE: "Your Wallet Server Title" # The title of your API
OPENAPI_INFO_DESCRIPTION: "Description of your Wallet Server functionalities"
OPENAPI_INFO_VERSION: "1.0.0" # API version
OPENAPI_INFO_TERMS_OF_SERVICE: "https://yourdomain.com/terms" # URL to the terms of service
OPENAPI_INFO_LICENSE_NAME: "Apache 2.0" # License name
OPENAPI_INFO_LICENSE_URL: "https://www.apache.org/licenses/LICENSE-2.0.html" # Link to license
OPENAPI_INFO_CONTACT_NAME: "Your Organization Name"
OPENAPI_INFO_CONTACT_URL: "https://yourdomain.com"
OPENAPI_INFO_CONTACT_EMAIL: "contact@yourdomain.com"
# CORS Configuration
WALLET_WDA_URL: "https://yourfrontenddomain.com" # Frontend domain for CORS policy
# Broker Configuration
BROKER_PROVIDER: "YourBrokerProvider" # e.g., scorpio, orion-ld
BROKER_EXTERNALDOMAIN: "https://yourbrokerdomain:port"
BROKER_INTERNALDOMAIN: "https://yourinternalbrokerdomain:port"
BROKER_PATHS_ENTITIES: "/ngsi-ld/v1/entities"
# Vault Configuration
VAULT_PROVIDER_NAME: "YourVaultProvider" # e.g., hashicorp
SPRING_CLOUD_VAULT_AUTHENTICATION: "token"
SPRING_CLOUD_VAULT_TOKEN: "YourVaultToken"
SPRING_CLOUD_VAULT_HOST: "vault"
SPRING_CLOUD_VAULT_SCHEME: "http"
SPRING_CLOUD_VAULT_PORT: "YourVaultPort"
SPRING_CLOUD_VAULT_KV_ENABLED: "true"
ports:
- "8080:8081"

```

## Resources
* [Google Java Style](https://github.com/checkstyle/checkstyle/blob/master/src/main/resources/google_checks.xml)

## Project Status
The project is currently at version **1.0.0** and is in a stable state.

## Contact
For any inquiries or collaboration, you can contact us at:
* **Email:** [info@in2.es](mailto:info@in2.es)
* **Name:** IN2, Ingeniería de la Información
* **Website:** [https://in2.es](https://in2.es)

## Creation Date and Update Dates
* **Creation Date:** February 19, 2024
12 changes: 10 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ sonar {
property 'sonar.organization', 'in2workspace'
property 'sonar.host.url', 'https://sonarcloud.io'
property 'sonar.coverage.exclusions',
'src/main/java/es/in2/wallet/WalletServerApplication.java, '
"src/main/java/es/in2/wallet/WalletServerApplication.java, " +
"src/main/java/es/in2/wallet/api/config/**, " +
"src/main/java/es/in2/wallet/api/model/**, " +
"src/main/java/es/in2/wallet/api/util/**, " +
"src/main/java/es/in2/wallet/api/ebsi/comformance/config/**"
}
}

Expand Down Expand Up @@ -147,7 +151,11 @@ tasks.jacocoTestReport {
afterEvaluate {
classDirectories.setFrom(files(classDirectories.files.collect {
fileTree(dir: it, exclude: [
'src/main/java/es/in2/wallet/WalletServerApplication.java'
"src/main/java/es/in2/wallet/WalletServerApplication.java",
"src/main/java/es/in2/wallet/api/config/**",
"src/main/java/es/in2/wallet/api/model/**",
"src/main/java/es/in2/wallet/api/util/**",
"src/main/java/es/in2/wallet/api/ebsi/comformance/config/**"
])
}))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static es.in2.wallet.api.util.MessageUtils.getUserIdFromToken;
import static es.in2.wallet.api.util.ApplicationUtils.getUserIdFromToken;

@Getter
@Component
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import java.util.UUID;

import static es.in2.wallet.api.util.MessageUtils.getCleanBearerToken;
import static es.in2.wallet.api.util.ApplicationUtils.getCleanBearerToken;

@Tag(name = "QR Codes", description = "QR code management API")
@Slf4j
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import java.util.List;
import java.util.UUID;

import static es.in2.wallet.api.util.MessageUtils.getCleanBearerAndUserIdFromToken;
import static es.in2.wallet.api.util.ApplicationUtils.getCleanBearerAndUserIdFromToken;

@RestController
@RequestMapping("/api/v2/credentials")
Expand All @@ -33,7 +33,7 @@ public class VerifiableCredentialController {
description = "Retrieve a list of Verifiable Credentials",
tags = {"Verifiable Credential Management"}
)
@ApiResponse(responseCode = "200", description = "Verifiable credential retrieved successfully.")
@ApiResponse(responseCode = "200", description = "Verifiable credentials retrieved successfully.")
@ApiResponse(responseCode = "400", description = "Invalid request.")
@ApiResponse(responseCode = "500", description = "Internal server error.")
public Mono<List<CredentialsBasicInfo>> getVerifiableCredentialList(@RequestHeader(HttpHeaders.AUTHORIZATION) String authorizationHeader) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
package es.in2.wallet.api.ebsi.comformance.configuration;
package es.in2.wallet.api.ebsi.comformance.config;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import es.in2.wallet.api.ebsi.comformance.configuration.properties.IdentityProviderProperties;
import es.in2.wallet.api.ebsi.comformance.config.properties.IdentityProviderProperties;
import es.in2.wallet.api.service.DidKeyGeneratorService;
import es.in2.wallet.api.service.KeyGenerationService;
import es.in2.wallet.api.service.UserDataService;
import es.in2.wallet.api.util.MessageUtils;
import es.in2.wallet.api.util.ApplicationUtils;
import es.in2.wallet.broker.service.BrokerService;
import es.in2.wallet.vault.service.VaultService;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.PostConstruct;
import lombok.RequiredArgsConstructor;
Expand All @@ -23,7 +21,9 @@
import java.time.Duration;
import java.util.*;

import static es.in2.wallet.api.util.MessageUtils.*;
import static es.in2.wallet.api.util.ApplicationUtils.postRequest;
import static es.in2.wallet.api.util.MessageUtils.CONTENT_TYPE;
import static es.in2.wallet.api.util.MessageUtils.CONTENT_TYPE_URL_ENCODED_FORM;

@Component
@RequiredArgsConstructor
Expand All @@ -32,9 +32,7 @@ public class EbsiConfig
{
private final ObjectMapper objectMapper;
private final IdentityProviderProperties identityProviderProperties;
private final KeyGenerationService keyGenerationService;
private final DidKeyGeneratorService didKeyGeneratorService;
private final VaultService vaultService;
private final BrokerService brokerService;
private final UserDataService userDataService;

Expand All @@ -43,9 +41,9 @@ public class EbsiConfig
@PostConstruct
@Tag(name = "EbsiConfig", description = "Generate Did for ebsi purposes")
public void init(){
generateDid().subscribe(did -> this.didForEbsi = did);
generateEbsiDid().subscribe(did -> this.didForEbsi = did);
}
private Mono<String> generateDid(){
private Mono<String> generateEbsiDid(){
String processId = UUID.randomUUID().toString();
MDC.put("processId", processId);
List<Map.Entry<String, String>> headers = new ArrayList<>();
Expand Down Expand Up @@ -74,14 +72,14 @@ private Mono<String> generateDid(){

return Mono.just(token);
})
.flatMap(MessageUtils::getUserIdFromToken)
.flatMap(ApplicationUtils::getUserIdFromToken)
.flatMap(userId -> brokerService.getEntityById(processId, userId)
.flatMap(optionalEntity -> optionalEntity
.map(entity -> getDidForUserAlreadyCreated(processId, userId))
.orElseGet(() ->
generateAndSaveKeyPair()
.flatMap(map -> createAndUpdateUser(processId, userId, map.get("did"))
.thenReturn(map.get("did"))
generateDid()
.flatMap(did -> createAndUpdateUser(processId, userId, did)
.thenReturn(did)
)
)
)
Expand All @@ -95,10 +93,8 @@ private Mono<String> generateDid(){


}
private Mono<Map<String, String>> generateAndSaveKeyPair() {
return keyGenerationService.generateES256r1ECKeyPair()
.flatMap(didKeyGeneratorService::generateDidKeyJwkJcsPubWithFromKeyPair)
.flatMap(map -> vaultService.saveSecret(map).thenReturn(map));
private Mono<String> generateDid() {
return didKeyGeneratorService.generateDidKeyJwkJcsPub();
}

private Mono<Void> createAndUpdateUser(String processId, String userId, String did) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package es.in2.wallet.api.ebsi.comformance.configuration.properties;
package es.in2.wallet.api.ebsi.comformance.config.properties;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package es.in2.wallet.api.ebsi.comformance.controller;

import es.in2.wallet.api.ebsi.comformance.facade.impl.EbsiCredentialIssuanceServiceFacadeImpl;
import es.in2.wallet.api.ebsi.comformance.facade.EbsiCredentialServiceFacade;
import es.in2.wallet.api.ebsi.comformance.model.CredentialOfferContent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -12,25 +12,30 @@

import java.util.UUID;

import static es.in2.wallet.api.util.MessageUtils.getCleanBearerToken;
import static es.in2.wallet.api.util.ApplicationUtils.getCleanBearerToken;


@Slf4j
@RestController
@RequestMapping("/api/v2/request-credential")
@RequiredArgsConstructor
public class CredentialIssuanceController {

private final EbsiCredentialIssuanceServiceFacadeImpl ebsiCredentialIssuanceServiceFacade;
private final EbsiCredentialServiceFacade ebsiCredentialIssuanceServiceFacade;

/**
* Processes a request for a verifiable credential when the credential offer is received via a redirect.
* This endpoint is designed to handle the scenario where a user is redirected to this service with a credential
* offer URI, as opposed to receiving the offer directly from scanning a QR code.
*/
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Mono<Void> requestVerifiableCredential(@RequestHeader(HttpHeaders.AUTHORIZATION) String authorizationHeader,
@RequestBody CredentialOfferContent credentialOfferContent) {
String processId = UUID.randomUUID().toString();
MDC.put("processId", processId);
return getCleanBearerToken(authorizationHeader)
.flatMap(authorizationToken ->
ebsiCredentialIssuanceServiceFacade.identifyAuthMethod(processId, authorizationToken, credentialOfferContent.credentialOfferUri()));
.flatMap(authorizationToken -> ebsiCredentialIssuanceServiceFacade.identifyAuthMethod(processId, authorizationToken, credentialOfferContent.credentialOfferUri()));
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package es.in2.wallet.api.ebsi.comformance.controller;

import es.in2.wallet.api.ebsi.comformance.configuration.EbsiConfig;
import es.in2.wallet.api.ebsi.comformance.config.EbsiConfig;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

import reactor.core.publisher.Mono;

public interface EbsiCredentialIssuanceServiceFacade {
public interface EbsiCredentialServiceFacade {
Mono<Void> identifyAuthMethod(String processId, String authorizationToken, String qrContent);
}
Loading

0 comments on commit b5fc778

Please sign in to comment.