├── .github ├── dependabot.yml └── workflows │ ├── codeql.yml │ ├── publish.yml │ └── test.yml ├── .gitignore ├── LICENSE ├── README.md ├── VERSION ├── examples └── demo-app-hibernate-encryption │ ├── README.md │ ├── pom.xml │ ├── run.sh │ └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── demo │ │ │ └── app │ │ │ ├── DemoApplication.java │ │ │ ├── InterceptorConfig.java │ │ │ ├── controller │ │ │ └── MainController.java │ │ │ ├── dal │ │ │ ├── Customer.java │ │ │ └── CustomerRepository.java │ │ │ └── service │ │ │ └── CustomerService.java │ └── resources │ │ └── application.properties │ └── test │ ├── java │ └── com │ │ └── demo │ │ └── app │ │ ├── CollectionSetup.java │ │ └── service │ │ └── CustomerServiceTest.java │ └── resources │ └── application-test.properties └── sdk ├── Makefile ├── README.md ├── client ├── README.md ├── pom.xml └── src │ ├── main │ └── java │ │ └── com │ │ └── piiano │ │ └── vault │ │ └── client │ │ ├── CryptoClient.java │ │ ├── ObjectClient.java │ │ ├── TokenClient.java │ │ ├── VaultClient.java │ │ └── model │ │ ├── AccessReason.java │ │ ├── AddObjectParams.java │ │ ├── AddObjectsParams.java │ │ ├── CommonParams.java │ │ ├── DecryptParams.java │ │ ├── DeleteObjectParams.java │ │ ├── DeleteObjectsParams.java │ │ ├── DeleteTokensParams.java │ │ ├── DetokenizeParams.java │ │ ├── EncryptParams.java │ │ ├── GetObjectParams.java │ │ ├── HashParams.java │ │ ├── ListObjectsParams.java │ │ ├── RotateTokensParams.java │ │ ├── SearchObjectsParams.java │ │ ├── SearchTokensParams.java │ │ ├── TokenQuery.java │ │ ├── TokenizeParams.java │ │ ├── UpdateEncryptedParams.java │ │ ├── UpdateObjectParams.java │ │ ├── UpdateObjectsParams.java │ │ └── UpdateTokensParams.java │ └── test │ └── java │ └── com │ └── piiano │ └── vault │ └── client │ ├── CollectionSetup.java │ ├── CryptoClientTest.java │ ├── DefaultClient.java │ ├── ObjectClientTest.java │ ├── TokenClientTest.java │ └── VaultClientTest.java ├── config.yaml ├── hibernate-encryption ├── README.md ├── pom.xml └── src │ └── main │ └── java │ └── com │ └── piiano │ └── vault │ └── orm │ └── encryption │ ├── Encrypted.java │ ├── Encryptor.java │ ├── Transformation.java │ └── TransformationInterceptor.java └── patches └── pom.patch /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | 8 | - package-ecosystem: "maven" 9 | directory: "/sdk/client" 10 | schedule: 11 | interval: "weekly" 12 | 13 | - package-ecosystem: "maven" 14 | directory: "/sdk/hibernate-encryption" 15 | schedule: 16 | interval: "weekly" 17 | 18 | - package-ecosystem: "maven" 19 | directory: "/examples/demo-app-hibernate-encryption" 20 | schedule: 21 | interval: "weekly" 22 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL 2 | run-name: ${{ github.workflow }} (${{ github.head_ref || github.ref_name }}) 3 | 4 | on: 5 | push: 6 | branches: ["main"] 7 | pull_request: 8 | # The branches below must be a subset of the branches above 9 | branches: ["main"] 10 | schedule: 11 | - cron: "27 18 * * 2" 12 | workflow_dispatch: 13 | 14 | jobs: 15 | analyze: 16 | name: Analyze 17 | runs-on: ubuntu-latest 18 | permissions: 19 | actions: read 20 | contents: read 21 | security-events: write 22 | 23 | strategy: 24 | fail-fast: false 25 | matrix: 26 | language: ["java"] 27 | 28 | steps: 29 | - name: Checkout repository 30 | uses: actions/checkout@v4 31 | 32 | # Initializes the CodeQL tools for scanning. 33 | - name: Initialize CodeQL 34 | uses: github/codeql-action/init@v3 35 | with: 36 | languages: ${{ matrix.language }} 37 | 38 | - name: Install java 39 | uses: actions/setup-java@v4 40 | with: 41 | java-version: 8 42 | distribution: zulu 43 | cache: maven 44 | 45 | - name: Prepare. 46 | working-directory: sdk 47 | run: make 48 | 49 | - name: Perform CodeQL Analysis 50 | uses: github/codeql-action/analyze@v3 51 | with: 52 | category: "/language:${{matrix.language}}" 53 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | run-name: ${{ github.workflow }} (${{ github.head_ref || github.ref_name }}) 3 | 4 | on: 5 | workflow_dispatch: 6 | inputs: 7 | vault_version: 8 | description: Vault version 9 | required: true 10 | bump-package: 11 | description: Bump package version 12 | type: choice 13 | required: false 14 | default: patch 15 | options: [ none, patch, minor, major ] 16 | 17 | jobs: 18 | build-n-publish: 19 | runs-on: ubuntu-latest 20 | services: 21 | vault: 22 | image: piiano/pvault-dev:${{ inputs.vault_version }} 23 | env: 24 | PVAULT_SERVICE_LICENSE: ${{ secrets.PVAULT_SERVICE_LICENSE }} 25 | PVAULT_SENTRY_ENABLE: true 26 | PVAULT_LOG_CUSTOMER_IDENTIFIER: "piiano" 27 | PVAULT_LOG_CUSTOMER_ENV: "VAULT-JAVA" 28 | ports: 29 | - 8123:8123 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v4 33 | with: 34 | # By default, the ref is the commit hash that triggered the original workflow. 35 | # Meaning it is missing changes that are committed by the workflow itself. 36 | # Explicitly set ref to the branch name, so we pull the latest changes committed by the CI. 37 | ref: ${{ github.ref_name }} 38 | token: ${{ secrets.CICD_RELEASES_PAT }} 39 | 40 | - name: Set up Java & Maven 41 | uses: actions/setup-java@v4 42 | with: # running setup-java again overwrites the settings.xml 43 | java-version: 8 44 | distribution: zulu 45 | cache: maven 46 | server-id: ossrh # Value of the distributionManagement/repository/id field of the pom.xml 47 | server-username: OSSRH_USERNAME # env variable for username in deploy 48 | server-password: OSSRH_TOKEN # env variable for token in deploy 49 | gpg-passphrase: MAVEN_GPG_PASSPHRASE # env variable for GPG private key passphrase 50 | gpg-private-key: ${{ secrets.MAVEN_GPG_PRIVATE_KEY }} # Value of the GPG private key to import 51 | 52 | - name: Calculate versions 53 | id: versions 54 | run: | 55 | source VERSION 56 | echo "old_vault_version=${VAULT_VERSION}" >> $GITHUB_OUTPUT 57 | echo "old_package_version=${PACKAGE_VERSION}" >> $GITHUB_OUTPUT 58 | if [[ "${{ inputs.bump-package }}" != "none" ]]; then 59 | echo "package_version=$(npx --yes semver -i ${{ inputs.bump-package }} ${PACKAGE_VERSION})" >> $GITHUB_OUTPUT 60 | fi 61 | 62 | - name: Bump package version in config file for openapi 63 | if: inputs.bump-package != 'none' 64 | working-directory: sdk 65 | run: | 66 | sed -i "s/artifactVersion: \"${{ steps.versions.outputs.old_package_version }}/artifactVersion: \"${{ steps.versions.outputs.package_version }}/g" config.yaml 67 | 68 | - name: Generate openapi 69 | working-directory: sdk 70 | run: | 71 | make generate-openapi VAULT_VERSION=${{ inputs.vault_version }} 72 | sudo chmod 777 ./openapi 73 | git apply patches/*.patch 74 | 75 | - name: Build & test openapi 76 | working-directory: sdk/openapi 77 | run: mvn -B clean install 78 | 79 | - name: Publish openapi 80 | if: inputs.bump-package != 'none' 81 | working-directory: sdk/openapi 82 | run: mvn deploy -B -P sign-artifacts -DskipTests 83 | env: 84 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 85 | OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }} 86 | MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} 87 | 88 | - name: Bump version of client pom.xml 89 | if: inputs.bump-package != 'none' 90 | working-directory: sdk/client 91 | run: mvn versions:set -DnewVersion=${{ steps.versions.outputs.package_version }} 92 | 93 | - name: Build & test client 94 | working-directory: sdk/client 95 | run: mvn -B clean install 96 | 97 | - name: Publish client 98 | if: inputs.bump-package != 'none' 99 | working-directory: sdk/client 100 | run: mvn deploy -B -P sign-artifacts -DskipTests 101 | env: 102 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 103 | OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }} 104 | MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} 105 | 106 | - name: Bump version of hibernate-encryption pom.xml 107 | if: inputs.bump-package != 'none' 108 | working-directory: sdk/hibernate-encryption 109 | run: mvn versions:set -DnewVersion=${{ steps.versions.outputs.package_version }} 110 | 111 | - name: Build & test hibernate-encryption 112 | working-directory: sdk/hibernate-encryption 113 | run: mvn -B clean install 114 | 115 | - name: Publish hibernate-encryption 116 | if: inputs.bump-package != 'none' 117 | working-directory: sdk/hibernate-encryption 118 | run: mvn deploy -B -P sign-artifacts -DskipTests 119 | env: 120 | OSSRH_USERNAME: ${{ secrets.OSSRH_USERNAME }} 121 | OSSRH_TOKEN: ${{ secrets.OSSRH_TOKEN }} 122 | MAVEN_GPG_PASSPHRASE: ${{ secrets.MAVEN_GPG_PASSPHRASE }} 123 | 124 | - name: Update demo-app-hibernate-encryption 125 | if: inputs.bump-package != 'none' 126 | working-directory: examples/demo-app-hibernate-encryption 127 | run: sed -i "s/${{ steps.versions.outputs.old_package_version }}/${{ steps.versions.outputs.package_version }}/g" pom.xml 128 | 129 | - name: Update Makefile 130 | if: inputs.bump-package != 'none' 131 | working-directory: sdk 132 | run: sed -i "s/VAULT_VERSION ?= ${{ steps.versions.outputs.old_vault_version }}/VAULT_VERSION ?= ${{ inputs.vault_version }}/g" Makefile 133 | 134 | - name: Update README files 135 | if: inputs.bump-package != 'none' 136 | working-directory: sdk 137 | run: sed -i "s/compatible with Vault ${{ steps.versions.outputs.old_vault_version }}/compatible with Vault ${{ inputs.vault_version }}/g" README.md client/README.md hibernate-encryption/README.md 138 | 139 | - name: Update VERSION file 140 | if: inputs.bump-package != 'none' 141 | run: echo -e "PACKAGE_VERSION=${{ steps.versions.outputs.package_version }}\nVAULT_VERSION=${{ inputs.vault_version }}" > VERSION 142 | # 143 | - name: Commit version changes and push 144 | if: inputs.bump-package != 'none' 145 | run: | 146 | git config --global user.email "cicd@piiano.com" 147 | git config --global user.name "Github Actions" 148 | git add VERSION 149 | git add sdk/config.yaml 150 | git add sdk/Makefile 151 | git add sdk/README.md 152 | git add sdk/client/pom.xml 153 | git add sdk/client/README.md 154 | git add sdk/hibernate-encryption/pom.xml 155 | git add sdk/hibernate-encryption/README.md 156 | git add examples/demo-app-hibernate-encryption/pom.xml 157 | git commit -m "Update publish version to ${{ steps.versions.outputs.package_version }} and vault version to ${{ inputs.vault_version }}" 158 | git push 159 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test all 2 | run-name: ${{ github.workflow }} (${{ github.head_ref || github.ref_name }}) 3 | 4 | on: 5 | push: 6 | # Run for all branches excluding dependabot branches. Do NOT run for tags. 7 | branches-ignore: 8 | - "dependabot/**" 9 | 10 | jobs: 11 | test-sdk: 12 | runs-on: ubuntu-latest 13 | services: 14 | vault: 15 | image: piiano/pvault-dev:latest 16 | env: 17 | PVAULT_SERVICE_LICENSE: ${{ secrets.PVAULT_SERVICE_LICENSE }} 18 | PVAULT_SENTRY_ENABLE: true 19 | PVAULT_LOG_CUSTOMER_IDENTIFIER: "piiano" 20 | PVAULT_LOG_CUSTOMER_ENV: "VAULT-JAVA" 21 | ports: 22 | - 8123:8123 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v4 26 | 27 | - name: Install java 28 | uses: actions/setup-java@v4 29 | with: 30 | java-version: 8 31 | distribution: zulu 32 | cache: maven 33 | 34 | - name: Build all 35 | working-directory: sdk 36 | run: make 37 | 38 | - name: Test client 39 | working-directory: sdk/client 40 | run: mvn test 41 | 42 | - name: Test hibernate-encryption 43 | working-directory: sdk/hibernate-encryption 44 | run: mvn test 45 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | openapi.yaml 2 | openapi/ 3 | 4 | # IDE 5 | .idea 6 | .vscode 7 | *.iml 8 | *.class 9 | 10 | # Build files 11 | **/target 12 | target 13 | .gradle 14 | build 15 | pom.xml.versionsBackup 16 | 17 | # Log file 18 | *.log 19 | 20 | # BlueJ files 21 | *.ctxt 22 | 23 | # Mobile Tools for Java (J2ME) 24 | .mtj.tmp/ 25 | 26 | # Package Files # 27 | *.jar 28 | *.war 29 | *.nar 30 | *.ear 31 | *.zip 32 | *.tar.gz 33 | *.rar 34 | 35 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 36 | hs_err_pid* 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Piiano 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | 6 | Piiano Vault 7 | 8 | 9 |

10 | 11 | # Piiano Vault 12 | 13 | **The secure home for sensitive personal data** 14 | 15 | Safely store sensitive personal data in your own cloud environment with automated compliance controls. [More details](#about-piiano-vault) 16 | 17 | # Vault-java 18 | 19 | The code in this repository contains source code for Vault Java packages and examples of use: 20 | 21 | 1. [Vault Java sdk](./sdk) to connect to the Vault. 22 | 1. [Vault Java Hibernate example](./examples/demo-app-hibernate-encryption) - runnable example to demonstrate usage of the SDK. 23 | 24 | # About Piiano Vault 25 | 26 | Piiano Vault is the secure home for sensitive personal data. It allows you to safely store sensitive personal data in your own cloud environment with automated compliance controls. 27 | 28 | Vault is deployed within your own architecture, next to other DBs used by the applications, and should be used to store the most critical sensitive personal data, such as credit cards and bank account numbers, names, emails, national IDs (e.g. SSN), phone numbers, etc. 29 | 30 | The main benefits are: 31 | 32 | - Field level encryption, including key rotation. 33 | - Searchability is allowed over the encrypted data. 34 | - Full audit log for all data accesses. 35 | - Granular access controls. 36 | - Easy masking and tokenization of data. 37 | - Out of the box privacy compliance functionality. 38 | 39 | More details can be found [on our website](https://piiano.com/pii-data-privacy-vault/) and on the [developers portal](https://piiano.com/docs/). 40 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | PACKAGE_VERSION=1.3.8 2 | VAULT_VERSION=1.15.1 3 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | 6 | Piiano Vault 7 | 8 | 9 |

10 | 11 | # Demo application using Piiano vault hibernate encryption 12 | 13 | Replacing the sensitive personal information in the application DB with vault encrypted values. 14 | 15 | At this project the vault is being integrated transparently to the application at the ORM level. 16 | This level of integration is suitable for applications that are using ORM to access the DB, when other use cases of accessing the DB directly should be handled at the application level. 17 | 18 | ## Requirements 19 | 20 | 1. Java JDK 1.8+ 21 | 1. Maven (3.8.3+)/Gradle (7.2+) 22 | 1. Docker 23 | 1. Vault license - get a free trial license from [get-started](https://piiano.com/docs/guides/get-started) and set it to an environment variable `PVAULT_SERVICE_LICENSE`. 24 | 1. Mac or Linux machine. For Windows, you will need a WSL2 console. 25 | 26 | ## Compiling the application 27 | 28 | Run: `mvn clean install -DskipTests` 29 | To run it with tests: `mvn clean install` 30 | 31 | **NOTE** To run tests you need to first run vault. See [get-started](https://piiano.com/docs/guides/get-started) guide. 32 | 33 | ## Running the application 34 | 35 | The demo application can be either run automatically by our provided script or manually. 36 | **Optional:** configure non-default network parameters by setting `APP_PORT`, `MYSQL_PORT`, and/or `DOCKER_LOCALHOST` (e.g. to 172.17.0.1 if `host.docker.internal` isn't working). 37 | 38 | ### One liner application running 39 | 40 | Run locally using `./run.sh`. 41 | To enable interactive mode, run `./run.sh -i`. In this mode you will need to press `` after every action. 42 | 43 | ### Running the application manually 44 | 45 | 1. Run: `mvn clean install -DskipTests` 46 | 1. Run Mysql: 47 | ```commandLine 48 | docker run --name mysql -e MYSQL_ROOT_PASSWORD=rootpass -p 3306:3306 -d mysql:8.0.30 49 | ``` 50 | You will require mysql CLI. If you don't have it installed you can run it from the mysql container: `docker exec -it mysql mysql` 51 | 1. Create the mysql Database ([taken from here](https://spring.io/guides/gs/accessing-data-mysql/#initial)): 52 | ```commandLine 53 | mysql --password 54 | create database app_db; 55 | create user 'springuser'@'%' identified by 'userpass'; 56 | grant all on app_db.* to 'springuser'@'%'; 57 | ``` 58 | Note that the app connects to mysql using configuration in src/main/resources/application.properties 59 | ``` 60 | spring.datasource.url=jdbc:mysql://localhost:3306/app_db 61 | spring.datasource.username=springuser 62 | spring.datasource.password=userpass 63 | ``` 64 | 1. Install Piiano vault 65 | 1. Install the Piiano Vault docker image by following the first step of the [get-started](https://piiano.com/docs/guides/get-started) guide. 66 | 2. Create a collection for the customer's sensitive data 67 | ``` 68 | pvault collection add --collection-pvschema " 69 | customers PERSONS ( 70 | name NAME, 71 | phone PHONE_NUMBER 72 | )" 73 | ``` 74 | 1. Run the Piiano ORM Demo: 75 | ``` 76 | java -jar ~/.m2/repository/com/piiano/example/demo-app-hibernate-encryption/0.0.1-SNAPSHOT/demo-app-hibernate-encryption-0.0.1-SNAPSHOT.jar 77 | ``` 78 | 1. Add customers by calling the REST API and filling the details: 79 | ``` 80 | http://localhost:8090/add-customer?name=${name}&email=${email}&phone=${phone}&ssn=${ssn}&dob=${dob}&state=${state} 81 | ``` 82 | 83 | ### Vault ORM Annotations 84 | 85 | The hibernate-encryption jar contains the following annotations that you can use to integrate your entities seamlessly with Vault: 86 | - `@Type(type = "Encrypted")` - marks a field as encrypted. 87 | The field will be encrypted when persisted to the DB and decrypted when retrieved from the DB. 88 | You can optionally specify the name of the collection to use for encryption like so: 89 | `@Type(type = "Encrypted", parameters = {@Parameter(name = COLLECTION, value = "customers")})` 90 | If the collection name is not specified, the name of the Table specified in the `@Table` annotation will be used. 91 | - `@Transformation` - marks a field as a transformation of an encrypted property. 92 | The field will be automatically be decrypted and transformed by Vault when retrieved from the DB. 93 | You must specify the name of the encrypted property whose value will be transformed and the transformer to apply like so: 94 | `@Transformation(property = "email", transformer = "mask")` 95 | This will decrypt the encrypted value of the `email` property and apply the `mask` transformer to it. 96 | Note: You must also apply the `@Transient` annotation to the field so that it is not persisted to the DB. 97 | 98 | In order to use the `@Transformation` annotation, you must inject the `TransformerInterceptor` bean into your application context. 99 | This can be done by adding the following to your Spring configuration: 100 | 101 | ```java 102 | @Configuration 103 | @ComponentScan(" com.piiano.vault.orm.encryption") 104 | public class InterceptorConfig { 105 | @Bean 106 | public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(TransformationInterceptor interceptor) { 107 | return props -> props.put("hibernate.session_factory.interceptor", interceptor); 108 | } 109 | } 110 | ``` 111 | 112 | `TransformerInterceptor` intercepts the loading of all entities from the DB and decrypts and transforms the fields marked with the `@Transformation` annotation. 113 | It is not required if you are not using the `@Transformation` annotation in any field. 114 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | 7 | org.springframework.boot 8 | spring-boot-starter-parent 9 | 2.7.0 10 | 11 | 12 | com.piiano.example 13 | demo-app-hibernate-encryption 14 | 0.0.1-SNAPSHOT 15 | demo-app-hibernate-encryption 16 | demo app using vault hibernate encryption 17 | 18 | 19 | 1.3.3 20 | 8 21 | ${java.version} 22 | ${java.version} 23 | 33.3.1-jre 24 | 1.18.34 25 | 8.0.33 26 | 27 | 28 | 29 | 30 | com.piiano.vault 31 | hibernate-encryption 32 | ${vault-java.version} 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter-data-jpa 37 | ${project.parent.version} 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-web 42 | ${project.parent.version} 43 | 44 | 45 | mysql 46 | mysql-connector-java 47 | ${mysql-connector-java.version} 48 | runtime 49 | 50 | 51 | com.google.guava 52 | guava 53 | ${guava.version} 54 | 55 | 56 | org.projectlombok 57 | lombok 58 | ${lombok.version} 59 | provided 60 | 61 | 62 | 63 | 64 | com.piiano.vault 65 | client 66 | ${vault-java.version} 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-starter-test 71 | ${project.parent.version} 72 | test 73 | 74 | 75 | com.h2database 76 | h2 77 | test 78 | 79 | 80 | junit 81 | junit 82 | test 83 | 84 | 85 | 86 | 87 | 88 | 89 | org.springframework.boot 90 | spring-boot-maven-plugin 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # APP 4 | export APP_PORT=${APP_PORT:-8090} 5 | BASE_URL="http://localhost:${APP_PORT}/demo" 6 | 7 | # MySQL 8 | MYSQL_USER=springuser 9 | MYSQL_ROOT_PASS=rootpass 10 | MYSQL_PASS=userpass 11 | MYSQL_DBNAME=app_db 12 | export MYSQL_PORT=${MYSQL_PORT:-3306} 13 | 14 | # Docker localhost 15 | DOCKER_LOCALHOST=${DOCKER_LOCALHOST:-host.docker.internal} # or use 172.17.0.1 16 | 17 | # Vault 18 | source ../../VERSION 19 | echo Running with vault version: "$VAULT_VERSION" 20 | export PVAULT_PORT=${PVAULT_PORT:-8123} 21 | PVAULT_CLI="docker run --rm -i -v $(pwd):/pwd -w /pwd -e PVAULT_ADDR=http://${DOCKER_LOCALHOST}:${PVAULT_PORT} piiano/pvault-cli:${VAULT_VERSION}" 22 | 23 | # Run as root and also wait allow for time until mysql is up 24 | function mysql_cmd_initial() 25 | { 26 | # shellcheck disable=SC2034 27 | for i in {1..20} 28 | do 29 | output=`docker run -it --rm mysql mysql -h${DOCKER_LOCALHOST} -uroot -p${MYSQL_ROOT_PASS} -P${MYSQL_PORT} -e "show databases;"` 30 | if [ $? != "0" ] ; then 31 | echo ${output} | grep -q "ERROR 20" 32 | if [ $? != "0" ] ; then 33 | echo "Failed running SQL command." 34 | return 35 | fi 36 | echo "MySQL not ready yet. Sleep 5" 37 | sleep 5 38 | else 39 | echo "MySQL is ready" 40 | echo "${output}" 41 | break 42 | fi 43 | done 44 | } 45 | 46 | function mysql_cmd() 47 | { 48 | IS_ROOT=${1} 49 | CMD="${2}" 50 | 51 | if ${IS_ROOT} ; then 52 | U="" 53 | P="-p${MYSQL_ROOT_PASS}" 54 | DB="" 55 | else 56 | U="-u ${MYSQL_USER}" 57 | P="-p${MYSQL_PASS}" 58 | DB=${MYSQL_DBNAME} 59 | fi 60 | echo Running "${CMD}" 61 | docker run -it --rm mysql mysql -h${DOCKER_LOCALHOST} -P${MYSQL_PORT} ${DB} ${U} ${P} -e "${CMD}" 62 | } 63 | 64 | function add_customer() 65 | { 66 | name=$1 67 | email=$2 68 | phone=$3 69 | ssn=$4 70 | dob=$5 71 | state=$6 72 | 73 | printf "Adding customer ${name} with email ${email} and with phone ${phone} ... " 74 | curl -s "${BASE_URL}/add-customer?name=${name}&email=${email}&phone=${phone}&ssn=${ssn}&dob=${dob}&state=${state}" 75 | if [ $? != 0 ] ; then 76 | echo "Failed adding customer" 77 | else 78 | echo 79 | fi 80 | } 81 | 82 | function usage_and_exit() 83 | { 84 | echo "Usage: $0 -i : run in interactive mode" 85 | exit 1 86 | } 87 | 88 | function stop_all() 89 | { 90 | echo "stop pvault" 91 | docker rm -f pvault-dev 92 | echo "stop mysql" 93 | docker rm -f mysql 94 | if [[ $(jobs -p) ]]; then 95 | kill "$(jobs -p)" 96 | fi 97 | 98 | } 99 | 100 | function interrupted_callback() 101 | { 102 | echo "Interrupted ..." 103 | stop_all 104 | exit 0 105 | } 106 | 107 | function debug() 108 | { 109 | echo -e '\n--' $1 110 | if $INTERACTIVE_MODE ; then 111 | echo " to continue" 112 | read -r 113 | fi 114 | } 115 | 116 | # ------------- 117 | # M A I N 118 | # ------------- 119 | 120 | 121 | # trap ctrl-c and call the interrupted callback 122 | trap interrupted_callback INT 123 | INTERACTIVE_MODE=false 124 | if [ $# -gt "1" ] ; then 125 | usage_and_exit 126 | elif [ $# -eq "1" ] ; then 127 | if [ $1 = "-i" ] ; then 128 | INTERACTIVE_MODE=true 129 | echo "Enable interactive mode" 130 | else 131 | usage_and_exit 132 | fi 133 | fi 134 | 135 | # if JQ is missing, use just cat instead 136 | JQ=jq 137 | ${JQ} --version > /dev/null 2>&1 138 | if [ $? != 0 ] ; then 139 | JQ=cat 140 | fi 141 | 142 | # check for license key of Vault 143 | if [ -z $PVAULT_SERVICE_LICENSE ] ; then 144 | echo "Please first set environment variable: PVAULT_SERVICE_LICENSE" 145 | echo "Obtain a free license here: https://piiano.com/docs/guides/get-started#install-piiano-vault" 146 | exit 0 147 | else 148 | debug "license found in PVAULT_SERVICE_LICENSE" 149 | fi 150 | 151 | debug "stopping stale containers" 152 | stop_all 153 | 154 | debug "starting mysql" 155 | docker run --rm --name mysql -e MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASS} -p ${MYSQL_PORT}:3306 -d mysql:8.0.30 156 | mysql_cmd_initial 157 | mysql_cmd true "create database app_db; create user '${MYSQL_USER}'@'%' identified by '${MYSQL_PASS}'; grant all on ${MYSQL_DBNAME}.* to '${MYSQL_USER}'@'%';" 158 | 159 | # start vault 160 | debug "starting vault" 161 | docker run --rm --name pvault-dev -p "${PVAULT_PORT}":8123 \ 162 | -e PVAULT_SERVICE_LICENSE="${PVAULT_SERVICE_LICENSE}" -d piiano/pvault-dev:"${VAULT_VERSION}" 163 | 164 | # check for Vault version to ensure it is up - TBD 165 | until ${PVAULT_CLI} version > /dev/null 2>&1 166 | do 167 | echo "Waiting for the vault to start ..." 168 | sleep 1 169 | done 170 | 171 | debug "Adding new collection 'customers' with name and phone property" 172 | ${PVAULT_CLI} collection add --collection-pvschema " 173 | customers PERSONS ( 174 | name NAME, 175 | email EMAIL, 176 | phone PHONE_NUMBER, 177 | ssn SSN, 178 | dob STRING 179 | )" 180 | 181 | # run the app 182 | debug "Running the spring app: java -jar ~/.m2/repository/com/piiano/example/demo-app-hibernate-encryption/0.0.1-SNAPSHOT/demo-app-hibernate-encryption-0.0.1-SNAPSHOT.jar" 183 | java -jar ~/.m2/repository/com/piiano/example/demo-app-hibernate-encryption/0.0.1-SNAPSHOT/demo-app-hibernate-encryption-0.0.1-SNAPSHOT.jar \ 184 | --server.port="${APP_PORT}" --spring.datasource.url=jdbc:mysql://localhost:"${MYSQL_PORT}"/app_db & 185 | 186 | until curl -s "${BASE_URL}/all" 187 | do 188 | echo "Waiting for app at ${BASE_URL}/all" 189 | sleep 5 190 | done 191 | 192 | # Add some customers 193 | debug "Adding customers..." 194 | add_customer john john@exmaple.com 123-11111 853-11-9898 1989-08-08 AZ 195 | add_customer john john2@exmaple.com 123-22222 454-21-4355 1975-02-10 NY 196 | add_customer alice alice@exmaple.com 123-33333 383-83-6464 1999-09-09 CA 197 | add_customer bob bob@exmaple.com 123-44444 978-35-2138 1982-06-10 FL 198 | 199 | # Search customer by name=john 200 | debug "Search customer by name=john --> expecting 2 results:" 201 | curl -s "${BASE_URL}/find-customer-by-name?name=john" | ${JQ} 202 | if [ $? != 0 ] ; then 203 | echo "Failed find customer by name" 204 | fi 205 | 206 | # Get all customers 207 | debug "Get all customers --> Expecting 4 results:" 208 | curl -s "${BASE_URL}/all" | ${JQ} 209 | if [ $? != 0 ] ; then 210 | echo "Failed get all customers" 211 | fi 212 | 213 | # Show mysql encrypted data 214 | debug "Showing encrypted data in mysql (note all columns are encrypted except the 'state' columns)" 215 | mysql_cmd false 'select * from customers where id=1\G' 216 | 217 | stop_all 218 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/src/main/java/com/demo/app/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.demo.app; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class DemoApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(DemoApplication.class, args); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/src/main/java/com/demo/app/InterceptorConfig.java: -------------------------------------------------------------------------------- 1 | package com.demo.app; 2 | 3 | import com.piiano.vault.orm.encryption.TransformationInterceptor; 4 | import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer; 5 | import org.springframework.context.annotation.Bean; 6 | import org.springframework.context.annotation.ComponentScan; 7 | import org.springframework.context.annotation.Configuration; 8 | 9 | // In order to support fields annotated @Transformation you must inject the TransformationInterceptor. 10 | // This configuration class is an example of how to do this. 11 | @Configuration 12 | @ComponentScan(" com.piiano.vault.orm.encryption") 13 | public class InterceptorConfig { 14 | @Bean 15 | public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(TransformationInterceptor interceptor) { 16 | return props -> props.put("hibernate.session_factory.interceptor", interceptor); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/src/main/java/com/demo/app/controller/MainController.java: -------------------------------------------------------------------------------- 1 | package com.demo.app.controller; 2 | 3 | import com.demo.app.dal.Customer; 4 | import com.demo.app.service.CustomerService; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Controller; 7 | import org.springframework.web.bind.annotation.GetMapping; 8 | import org.springframework.web.bind.annotation.RequestMapping; 9 | import org.springframework.web.bind.annotation.RequestParam; 10 | import org.springframework.web.bind.annotation.ResponseBody; 11 | 12 | import java.util.List; 13 | 14 | @Controller 15 | @RequestMapping(path="/demo") 16 | public class MainController { 17 | 18 | @Autowired 19 | private CustomerService customerService; 20 | 21 | @GetMapping(path="/all") 22 | public @ResponseBody Iterable getAllCustomers() { 23 | return customerService.getAllCustomers(); 24 | } 25 | 26 | @GetMapping(path="/add-customer") 27 | public @ResponseBody String addCustomer(Customer customer) { 28 | 29 | customerService.addCustomer(customer); 30 | return "Saved"; 31 | } 32 | 33 | @GetMapping(path="/update-customer") 34 | public @ResponseBody String updateCustomer(Customer customer) { 35 | 36 | if (customerService.updateCustomer(customer)) { 37 | return "Updated"; 38 | } 39 | return "Not Found"; 40 | } 41 | 42 | @GetMapping(path="/delete-customer") 43 | public @ResponseBody String deleteCustomer(@RequestParam Integer id) { 44 | if (customerService.deleteCustomer(id)) { 45 | return "Deleted"; 46 | } 47 | return "Not Found"; 48 | } 49 | 50 | @GetMapping(path="/find-customer-by-name") 51 | public @ResponseBody List findCustomerByName(@RequestParam String name) { 52 | 53 | return customerService.findCustomerByName(name); 54 | } 55 | 56 | @GetMapping(path="/find-customer-by-phone") 57 | public @ResponseBody List findCustomerByPhone(@RequestParam(name = "phone") String phone) { 58 | 59 | return customerService.findCustomerByPhone(phone); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/src/main/java/com/demo/app/dal/Customer.java: -------------------------------------------------------------------------------- 1 | package com.demo.app.dal; 2 | 3 | import com.piiano.vault.orm.encryption.Encrypted; 4 | import com.piiano.vault.orm.encryption.Transformation; 5 | import lombok.*; 6 | import org.hibernate.annotations.Parameter; 7 | import org.hibernate.annotations.Type; 8 | import org.hibernate.annotations.TypeDef; 9 | 10 | import javax.persistence.*; 11 | 12 | import static com.piiano.vault.orm.encryption.Encrypted.PROPERTY; 13 | 14 | @Table(name = "customers") 15 | @Entity 16 | @TypeDef(name = "Encrypted", typeClass = Encrypted.class) 17 | @Getter 18 | @Setter 19 | @AllArgsConstructor 20 | @NoArgsConstructor 21 | @Builder 22 | public class Customer { 23 | 24 | // The following properties are persisted in the database. 25 | // Those that are annotated with @Type(type = "Encrypted") will be encrypted by Vault and persisted as ciphertext. 26 | @Id 27 | @GeneratedValue(strategy=GenerationType.AUTO) 28 | private Integer id; 29 | 30 | @Column(name = "name") 31 | @Type(type = "Encrypted") 32 | private String name; 33 | 34 | @Column(name = "email") 35 | @Type(type = "Encrypted") 36 | private String email; 37 | 38 | @Column(name = "phone") 39 | @Type(type = "Encrypted") 40 | private String phone; 41 | 42 | @Column(name = "ssn") 43 | @Type(type = "Encrypted") 44 | private String ssn; 45 | 46 | @Column(name = "dob") 47 | @Type(type = "Encrypted") 48 | private String dob; 49 | 50 | @Column(name = "state") 51 | private String state; 52 | 53 | // The following properties are not persisted in the database. 54 | // They are automatically calculated by calling Vault to decrypt the field named by "property", 55 | // applying the transformer named by "transformer". 56 | @Transient 57 | @Transformation(property = "ssn", transformer = "mask") 58 | private String ssnMask; 59 | 60 | @Transient 61 | @Transformation(property = "email", transformer = "mask") 62 | private String emailMask; 63 | } 64 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/src/main/java/com/demo/app/dal/CustomerRepository.java: -------------------------------------------------------------------------------- 1 | package com.demo.app.dal; 2 | 3 | import org.springframework.data.repository.CrudRepository; 4 | 5 | import java.util.List; 6 | 7 | public interface CustomerRepository extends CrudRepository { 8 | 9 | List findCustomerByName(String name); 10 | 11 | List findCustomerByPhone(String phone); 12 | } 13 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/src/main/java/com/demo/app/service/CustomerService.java: -------------------------------------------------------------------------------- 1 | package com.demo.app.service; 2 | 3 | import com.demo.app.dal.Customer; 4 | import com.demo.app.dal.CustomerRepository; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.stereotype.Service; 7 | 8 | import java.util.List; 9 | import java.util.Optional; 10 | 11 | @Service 12 | public class CustomerService { 13 | 14 | @Autowired 15 | private CustomerRepository customerRepository; 16 | 17 | public Iterable getAllCustomers() { 18 | return customerRepository.findAll(); 19 | } 20 | 21 | public Optional getCustomer(Integer id) { 22 | return customerRepository.findById(id); 23 | } 24 | 25 | public void addCustomer(Customer customer) { 26 | customerRepository.save(customer); 27 | } 28 | 29 | public boolean updateCustomer(Customer customer) { 30 | if (customer.getId() != null && customerRepository.existsById(customer.getId())) { 31 | customerRepository.save(customer); 32 | return true; 33 | } 34 | return false; 35 | } 36 | 37 | public boolean deleteCustomer(Integer id) { 38 | if (customerRepository.existsById(id)) { 39 | customerRepository.deleteById(id); 40 | return true; 41 | } 42 | return false; 43 | } 44 | 45 | public List findCustomerByName(String name) { 46 | return customerRepository.findCustomerByName(name); 47 | } 48 | 49 | public List findCustomerByPhone(String phone) { 50 | return customerRepository.findCustomerByPhone(phone); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 2 | spring.datasource.url=jdbc:mysql://localhost:3306/app_db 3 | spring.datasource.username=springuser 4 | spring.datasource.password=userpass 5 | spring.jpa.hibernate.ddl-auto=update 6 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL8Dialect 7 | #spring.jpa.show-sql: true 8 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/src/test/java/com/demo/app/CollectionSetup.java: -------------------------------------------------------------------------------- 1 | package com.demo.app; 2 | 3 | import com.piiano.vault.client.openapi.ApiClient; 4 | import com.piiano.vault.client.openapi.ApiException; 5 | import com.piiano.vault.client.openapi.CollectionsApi; 6 | import com.piiano.vault.client.openapi.Configuration; 7 | import com.piiano.vault.client.openapi.model.Collection; 8 | import com.piiano.vault.client.openapi.model.Property; 9 | 10 | import java.util.Collections; 11 | 12 | public class CollectionSetup { 13 | 14 | private static final String collectionName = "customers"; 15 | 16 | public static void setUp() throws ApiException { 17 | addCollection(); 18 | } 19 | 20 | public static void tearDown() { 21 | deleteCollectionIfExists(); 22 | } 23 | 24 | private static Collection addCollection() throws ApiException { 25 | 26 | ApiClient pvaultClient = getApiClient(); 27 | CollectionsApi collectionsApi = new CollectionsApi(pvaultClient); 28 | 29 | deleteCollectionIfExists(); 30 | 31 | Collection collection = createCollection(); 32 | return collectionsApi.addCollection(collection).format("json").execute(); 33 | } 34 | 35 | private static void deleteCollectionIfExists() { 36 | ApiClient pvaultClient = getApiClient(); 37 | CollectionsApi collectionsApi = new CollectionsApi(pvaultClient); 38 | 39 | try { 40 | collectionsApi.deleteCollection(collectionName).execute(); 41 | } catch (ApiException e) { 42 | // Collection not found - do nothing. 43 | } 44 | } 45 | 46 | public static Collection createCollection() { 47 | return new Collection() 48 | .name(collectionName) 49 | .type(Collection.TypeEnum.PERSONS) 50 | .addPropertiesItem( 51 | new Property().name("name").dataTypeName("NAME").description("Name") 52 | .isEncrypted(true) 53 | ).addPropertiesItem( 54 | new Property().name("phone").dataTypeName("PHONE_NUMBER").description("Phone") 55 | .isEncrypted(true).isNullable(true) 56 | ).addPropertiesItem( 57 | new Property().name("ssn").dataTypeName("SSN").description("ssn") 58 | .isEncrypted(true).isNullable(true) 59 | ).addPropertiesItem( 60 | new Property().name("email").dataTypeName("EMAIL").description("ssn") 61 | .isEncrypted(true).isNullable(true) 62 | ); 63 | } 64 | 65 | private static ApiClient getApiClient() { 66 | // Create configuration, bearer auth and client API 67 | ApiClient pvaultClient = Configuration.getDefaultApiClient(); 68 | pvaultClient.setBasePath("http://localhost:8123"); 69 | pvaultClient.setBearerToken("pvaultauth"); 70 | pvaultClient.addDefaultHeader("Content-Type", "application/json"); 71 | return pvaultClient; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/src/test/java/com/demo/app/service/CustomerServiceTest.java: -------------------------------------------------------------------------------- 1 | package com.demo.app.service; 2 | 3 | import com.demo.app.CollectionSetup; 4 | import com.demo.app.dal.Customer; 5 | import com.google.common.collect.ImmutableList; 6 | import com.piiano.vault.client.openapi.ApiException; 7 | import org.assertj.core.util.Lists; 8 | import org.junit.jupiter.api.AfterEach; 9 | import org.junit.jupiter.api.BeforeEach; 10 | import org.junit.jupiter.api.Test; 11 | import org.springframework.beans.factory.annotation.Autowired; 12 | import org.springframework.boot.test.context.SpringBootTest; 13 | import org.springframework.test.context.TestPropertySource; 14 | 15 | import java.util.List; 16 | import java.util.stream.Collectors; 17 | import java.util.stream.StreamSupport; 18 | 19 | import static org.junit.jupiter.api.Assertions.assertEquals; 20 | 21 | @SpringBootTest 22 | @TestPropertySource(locations = "classpath:application-test.properties") 23 | class CustomerServiceTest { 24 | 25 | @Autowired 26 | private CustomerService customerService; 27 | 28 | @BeforeEach 29 | public void beforeEach() throws ApiException { 30 | CollectionSetup.setUp(); 31 | } 32 | 33 | @AfterEach 34 | public void afterEach() { 35 | CollectionSetup.tearDown(); 36 | } 37 | 38 | @Test 39 | public void testCreateAndFindCustomer() { 40 | 41 | customerService.addCustomer(getCustomer()); 42 | 43 | // Note that the customer name is "John" is marked as Encrypted and is therefore stored in your 44 | // database as a ciphertext value. And yet you can search for it using the plaintext value. 45 | List results = customerService.findCustomerByName("John"); 46 | assertEquals(1, results.size()); 47 | Customer actual = results.get(0); 48 | 49 | assertEquals("John", actual.getName()); 50 | assertEquals("123-45-6789", actual.getSsn()); 51 | assertEquals("david@gmail.com", actual.getEmail()); 52 | assertEquals("+888888888", actual.getPhone()); 53 | assertEquals("CA", actual.getState()); 54 | assertEquals("***-**-6789", actual.getSsnMask()); 55 | assertEquals("d****@gmail.com", actual.getEmailMask()); 56 | 57 | // Cleanup. 58 | 59 | List customerIds = results.stream() 60 | .map(Customer::getId) 61 | .collect(Collectors.toList()); 62 | 63 | deleteCustomers(customerIds); 64 | } 65 | 66 | @Test 67 | public void testCreateAndGetCustomer() { 68 | 69 | customerService.addCustomer(getCustomer()); 70 | 71 | List customerIds = StreamSupport.stream(customerService.getAllCustomers().spliterator(), false) 72 | .map(Customer::getId) 73 | .collect(Collectors.toList()); 74 | 75 | assertEquals(1, customerIds.size()); 76 | 77 | // Cleanup. 78 | deleteCustomers(customerIds); 79 | } 80 | 81 | @Test 82 | public void testCreateMultipleCustomers() { 83 | 84 | List customers = getCustomers(); 85 | customers.forEach(u -> customerService.addCustomer(u)); 86 | 87 | List customerIds = StreamSupport.stream(customerService.getAllCustomers().spliterator(), false) 88 | .map(Customer::getId) 89 | .collect(Collectors.toList()); 90 | 91 | assertEquals(3, customerIds.size()); 92 | 93 | // Cleanup. 94 | deleteCustomers(customerIds); 95 | } 96 | 97 | @Test 98 | public void testFindCustomersByName() { 99 | 100 | List customers = Lists.newArrayList(getCustomers()); 101 | customers.add(getCustomer()); 102 | 103 | customers.forEach(u -> customerService.addCustomer(u)); 104 | 105 | List customerIds = StreamSupport.stream(customerService.getAllCustomers().spliterator(), false) 106 | .map(Customer::getId) 107 | .collect(Collectors.toList()); 108 | 109 | assertEquals(4, customerIds.size()); 110 | 111 | List personNamedJohn = customerService.findCustomerByName("John"); 112 | assertEquals(2, personNamedJohn.size()); 113 | 114 | // Cleanup. 115 | deleteCustomers(customerIds); 116 | } 117 | 118 | @Test 119 | public void testFindCustomersByPhone() { 120 | 121 | List customers = Lists.newArrayList(getCustomers()); 122 | customers.add(getCustomer()); 123 | 124 | String phone = "+12345678"; 125 | for (int i = 0; i < customers.size(); i++) { 126 | if (i == 0) { 127 | continue; 128 | } 129 | customers.get(i).setPhone(phone); 130 | } 131 | 132 | customers.forEach(u -> customerService.addCustomer(u)); 133 | 134 | List customerIds = StreamSupport.stream(customerService.getAllCustomers().spliterator(), false) 135 | .map(Customer::getId) 136 | .collect(Collectors.toList()); 137 | 138 | assertEquals(4, customerIds.size()); 139 | 140 | List personNamedJohn = customerService.findCustomerByPhone(phone); 141 | assertEquals(3, personNamedJohn.size()); 142 | 143 | // Cleanup. 144 | deleteCustomers(customerIds); 145 | } 146 | 147 | @Test 148 | public void testUpdateCustomer() { 149 | 150 | List customers = Lists.newArrayList(getCustomers()); 151 | customers.forEach(u -> customerService.addCustomer(u)); 152 | 153 | List customerIds = StreamSupport.stream(customerService.getAllCustomers().spliterator(), false) 154 | .map(Customer::getId) 155 | .collect(Collectors.toList()); 156 | 157 | assertEquals(3, customerIds.size()); 158 | 159 | String newName = "Steven"; 160 | Customer customerToUpdate = new Customer(); 161 | customerToUpdate.setId(customerIds.get(0)); 162 | customerToUpdate.setName(newName); 163 | customerService.updateCustomer(customerToUpdate); 164 | 165 | List customer = customerService.findCustomerByName(newName); 166 | assertEquals(1, customer.size()); 167 | 168 | // Cleanup. 169 | deleteCustomers(customerIds); 170 | } 171 | 172 | @Test 173 | public void testDeleteCustomer() { 174 | 175 | List customers = Lists.newArrayList(getCustomers()); 176 | customers.forEach(u -> customerService.addCustomer(u)); 177 | 178 | List customerIds = StreamSupport.stream(customerService.getAllCustomers().spliterator(), false) 179 | .map(Customer::getId) 180 | .collect(Collectors.toList()); 181 | 182 | assertEquals(3, customerIds.size()); 183 | 184 | customerService.deleteCustomer(customerIds.get(0)); 185 | 186 | customerIds = StreamSupport.stream(customerService.getAllCustomers().spliterator(), false) 187 | .map(Customer::getId) 188 | .collect(Collectors.toList()); 189 | assertEquals(2, customerIds.size()); 190 | 191 | // Cleanup. 192 | deleteCustomers(customerIds); 193 | } 194 | 195 | private static Customer getCustomer() { 196 | Customer customer = new Customer(); 197 | customer.setName("John"); 198 | customer.setPhone("+8-888-88888"); 199 | customer.setState("CA"); 200 | customer.setSsn("123-45-6789"); 201 | customer.setEmail("david@gmail.com"); 202 | return customer; 203 | } 204 | 205 | private static List getCustomers() { 206 | Customer customer1 = getCustomer(); 207 | 208 | Customer customer2 = new Customer(); 209 | customer2.setName("Alice"); 210 | customer2.setPhone("+11111111"); 211 | customer2.setState("NY"); 212 | customer2.setSsn("123-45-6789"); 213 | 214 | Customer customer3 = new Customer(); 215 | customer3.setName("Bob"); 216 | customer3.setPhone("+22222222"); 217 | customer3.setState("AZ"); 218 | customer3.setSsn("321-45-6789"); 219 | 220 | return ImmutableList.of(customer1, customer2, customer3); 221 | } 222 | 223 | private void deleteCustomers(List customerIds) { 224 | customerIds.forEach(id -> customerService.deleteCustomer(id)); 225 | } 226 | } 227 | -------------------------------------------------------------------------------- /examples/demo-app-hibernate-encryption/src/test/resources/application-test.properties: -------------------------------------------------------------------------------- 1 | spring.datasource.driver-class-name=org.h2.Driver 2 | spring.datasource.url=jdbc:h2:mem:test 3 | spring.jpa.hibernate.ddl-auto=create-drop 4 | spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.H2Dialect 5 | -------------------------------------------------------------------------------- /sdk/Makefile: -------------------------------------------------------------------------------- 1 | .DEFAULT_GOAL := all 2 | 3 | VAULT_VERSION ?= 1.15.1 4 | OPENAPI_YAML := openapi.yaml 5 | CODEGEN_IMAGE := openapitools/openapi-generator-cli:v7.10.0 6 | CODEGEN_CONFIG_FILE := config.yaml 7 | OPENAPI_FOLDER := openapi 8 | CLIENT_FOLDER := client 9 | HIBERNATE_FOLDER := hibernate-encryption 10 | APP_FOLDER := ../examples/demo-app-hibernate-encryption 11 | 12 | 13 | $(OPENAPI_YAML): 14 | curl -L https://docs.piiano.com/v$(subst .,-,$(VAULT_VERSION))/assets/openapi.yaml --output $@ 15 | 16 | $(OPENAPI_FOLDER)/pom.xml: $(OPENAPI_YAML) $(CODEGEN_CONFIG_FILE) 17 | mkdir -p $(OPENAPI_FOLDER)/target 18 | docker run --rm -v "${PWD}:/pwd" $(CODEGEN_IMAGE) generate --additional-properties=useSingleRequestParameter=true \ 19 | -g java \ 20 | -i /pwd/$(OPENAPI_YAML) \ 21 | -c /pwd/$(CODEGEN_CONFIG_FILE) \ 22 | -o /pwd/$(OPENAPI_FOLDER) 23 | 24 | .PHONY: generate-openapi 25 | generate-openapi: $(OPENAPI_YAML) $(OPENAPI_FOLDER)/pom.xml 26 | mvn -f $(OPENAPI_FOLDER) clean install -DskipTests 27 | 28 | .PHONY: $(CLIENT_FOLDER) 29 | $(CLIENT_FOLDER): generate-openapi 30 | mvn -f $(CLIENT_FOLDER) clean install -DskipTests 31 | 32 | .PHONY: $(HIBERNATE_FOLDER) 33 | $(HIBERNATE_FOLDER): $(CLIENT_FOLDER) 34 | mvn -f $(HIBERNATE_FOLDER) clean install -DskipTests 35 | 36 | .PHONY: $(APP_FOLDER) 37 | $(APP_FOLDER): $(HIBERNATE_FOLDER) 38 | mvn -f $(APP_FOLDER) clean install -DskipTests 39 | 40 | .PHONY: run-vault 41 | run-vault: 42 | docker rm -f pvault-dev 43 | docker run --init \ 44 | --name pvault-dev \ 45 | --add-host='host.docker.internal:host-gateway' \ 46 | -p 8123:8123 \ 47 | -e PVAULT_SERVICE_LICENSE=${PVAULT_SERVICE_LICENSE} \ 48 | -e PVAULT_SENTRY_ENABLE=true \ 49 | -e PVAULT_LOG_CUSTOMER_IDENTIFIER="piiano" \ 50 | -e PVAULT_LOG_CUSTOMER_ENV="VAULT-JAVA" \ 51 | -d \ 52 | piiano/pvault-dev:$(VAULT_VERSION) 53 | sleep 5 54 | 55 | .PHONY: test-openapi 56 | test-openapi: generate-openapi 57 | mvn -f $(OPENAPI_FOLDER) test 58 | 59 | .PHONY: test-client 60 | test-client: $(CLIENT_FOLDER) 61 | mvn -f $(CLIENT_FOLDER) test 62 | 63 | .PHONY: test-hibernate 64 | test-hibernate: $(HIBERNATE_FOLDER) 65 | mvn -f $(HIBERNATE_FOLDER) test 66 | 67 | .PHONE: test-app 68 | test-app: $(APP_FOLDER) 69 | mvn -f $(APP_FOLDER) test 70 | 71 | .PHONY: test-all 72 | test-all: test-openapi run-vault test-client test-hibernate test-app 73 | 74 | .PHONY: clean 75 | clean: 76 | mvn -f $(CLIENT_FOLDER) clean 77 | mvn -f $(HIBERNATE_FOLDER) clean 78 | mvn -f $(APP_FOLDER) clean 79 | rm -f -r $(OPENAPI_FOLDER) 80 | rm -f $(OPENAPI_YAML) 81 | 82 | .PHONY: all 83 | all: $(APP_FOLDER) 84 | -------------------------------------------------------------------------------- /sdk/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | 6 | Piiano Vault 7 | 8 | 9 |

10 | 11 | # Piiano vault Java SDK 12 | 13 | 14 | ![Workflow status badge](https://github.com/piiano/vault-java/actions/workflows/test.yml/badge.svg?branch=main) 15 | ![Java version badge](https://img.shields.io/badge/java-8-blue) 16 | 17 | This folder contains SDKs that connect to the Vault. 18 | 19 | This package is compatible with Vault 1.14.0 20 | 21 | ## Compiling 22 | 23 | Run: `make` 24 | 25 | The Makefile will: 26 | 27 | 1. Auto generate the Openapi client 28 | 1. Create the Vault [Client](./client) using the auto generated client 29 | 1. Create the [Hibernate encryption](./hibernate-encryption/) package using the Client. 30 | 31 | ## Running tests 32 | 33 | An instance of the Vault must be running before tests could start. The Makefile does that automatically. 34 | 35 | Run: `make test` 36 | -------------------------------------------------------------------------------- /sdk/client/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | 6 | Piiano Vault 7 | 8 | 9 |

10 | 11 | # vault-client 12 | 13 | This package is compatible with Vault 1.14.0 14 | 15 | ## Compiling 16 | 17 | Run: `mvn clean install -DskipTests` 18 | 19 | ## Testing 20 | 21 | You will need to start Vault first. It is recommended to run testing from the Makefile in the [parent folder](./..). 22 | -------------------------------------------------------------------------------- /sdk/client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.piiano.vault 7 | client 8 | 1.3.8 9 | ${project.groupId}:${project.artifactId} 10 | Piiano vault sdk 11 | https://github.com/piiano/vault-java/tree/main/sdk/client 12 | jar 13 | 14 | 15 | scm:git:git@github.com/piiano/vault-java.git 16 | scm:git:git@github.com/piiano/vault-java.git 17 | https://github.com/piiano/vault-java 18 | 19 | 20 | 21 | 22 | MIT License 23 | https://github.com/piiano/vault-java/blob/main/LICENSE 24 | repo 25 | 26 | 27 | 28 | 29 | 30 | Piiano vault-java contributors 31 | info@piiano.com 32 | Piiano 33 | https://piiano.com/ 34 | 35 | 36 | 37 | 38 | 39 | com.piiano.vault 40 | openapi 41 | ${project.version} 42 | 43 | 44 | org.projectlombok 45 | lombok 46 | ${lombok.version} 47 | provided 48 | 49 | 50 | com.google.guava 51 | guava 52 | ${guava.version} 53 | 54 | 55 | junit 56 | junit 57 | ${junit.version} 58 | test 59 | 60 | 61 | org.junit.jupiter 62 | junit-jupiter 63 | ${junit-jupiter.version} 64 | test 65 | 66 | 67 | 68 | 69 | 8 70 | ${java.version} 71 | ${java.version} 72 | 73 | 1.18.34 74 | 33.3.1-jre 75 | 4.13.2 76 | 5.10.0 77 | 78 | 79 | 80 | 81 | ossrh 82 | https://s01.oss.sonatype.org/content/repositories/snapshots 83 | 84 | 85 | 86 | 87 | 88 | 89 | org.sonatype.plugins 90 | nexus-staging-maven-plugin 91 | 1.7.0 92 | true 93 | 94 | ossrh 95 | https://s01.oss.sonatype.org/ 96 | true 97 | 98 | 99 | 100 | org.apache.maven.plugins 101 | maven-source-plugin 102 | 3.3.0 103 | 104 | 105 | attach-sources 106 | 107 | jar-no-fork 108 | 109 | 110 | 111 | 112 | 113 | org.apache.maven.plugins 114 | maven-javadoc-plugin 115 | 3.6.2 116 | 117 | 118 | attach-javadocs 119 | 120 | jar 121 | 122 | 123 | 124 | 125 | none 126 | 127 | 128 | http.response.details 129 | a 130 | Http Response Details: 131 | 132 | 133 | 134 | 135 | 136 | org.apache.maven.plugins 137 | maven-surefire-plugin 138 | 3.5.2 139 | 140 | 141 | org.junit.jupiter 142 | junit-jupiter 143 | ${junit-jupiter.version} 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | sign-artifacts 153 | 154 | 155 | 156 | org.apache.maven.plugins 157 | maven-gpg-plugin 158 | 3.2.7 159 | 160 | 161 | sign-artifacts 162 | verify 163 | 164 | sign 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/CryptoClient.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client; 2 | 3 | import com.piiano.vault.client.model.*; 4 | import com.piiano.vault.client.openapi.ApiClient; 5 | import com.piiano.vault.client.openapi.ApiException; 6 | import com.piiano.vault.client.openapi.CryptoApi; 7 | import com.piiano.vault.client.openapi.model.*; 8 | 9 | import java.util.List; 10 | 11 | /** 12 | * Client for the Crypto API. 13 | */ 14 | public class CryptoClient { 15 | 16 | private final CryptoApi cryptoApi; 17 | 18 | public CryptoClient(ApiClient apiClient) { 19 | this.cryptoApi = new CryptoApi(apiClient); 20 | } 21 | 22 | public CryptoApi openapi() { 23 | return cryptoApi; 24 | } 25 | 26 | public List encrypt(EncryptParams encryptParams) throws ApiException { 27 | 28 | if (encryptParams.getAccessReason() == null) { 29 | throw new ApiException("Access reason is required"); 30 | } 31 | return this.cryptoApi.encrypt( 32 | encryptParams.getCollection(), 33 | encryptParams.getEncryptionRequest()) 34 | .reason(encryptParams.getAccessReason().getReason()) 35 | .adhocReason(encryptParams.getAccessReason().getAdhocReason()) 36 | .expirationSecs(encryptParams.getExpirationSecs()) 37 | .customAudit(encryptParams.getCustomAudit()) 38 | .reloadCache(encryptParams.isReloadCache()) 39 | .xTenantId(encryptParams.getXTenantId()) 40 | .execute(); 41 | } 42 | 43 | public List decrypt(DecryptParams decryptParams) throws ApiException { 44 | 45 | if (decryptParams.getAccessReason() == null) { 46 | throw new ApiException("Access reason is required"); 47 | } 48 | return this.cryptoApi.decrypt( 49 | decryptParams.getCollection(), 50 | decryptParams.getDecryptionRequests()) 51 | .reason(decryptParams.getAccessReason().getReason()) 52 | .adhocReason(decryptParams.getAccessReason().getAdhocReason()) 53 | .options(decryptParams.getOptions()) 54 | .customAudit(decryptParams.getCustomAudit()) 55 | .reloadCache(decryptParams.isReloadCache()) 56 | .xTenantId(decryptParams.getXTenantId()) 57 | .execute(); 58 | } 59 | 60 | public List updateEncrypted(UpdateEncryptedParams updateEncryptedParams) throws ApiException { 61 | 62 | if (updateEncryptedParams.getAccessReason() == null) { 63 | throw new ApiException("Access reason is required"); 64 | } 65 | return this.cryptoApi.updateEncrypted( 66 | updateEncryptedParams.getCollection(), 67 | updateEncryptedParams.getUpdateEncryptionRequests()) 68 | .reason(updateEncryptedParams.getAccessReason().getReason()) 69 | .adhocReason(updateEncryptedParams.getAccessReason().getAdhocReason()) 70 | .expirationSecs(updateEncryptedParams.getExpirationSecs()) 71 | .options(updateEncryptedParams.getOptions()) 72 | .customAudit(updateEncryptedParams.getCustomAudit()) 73 | .reloadCache(updateEncryptedParams.isReloadCache()) 74 | .xTenantId(updateEncryptedParams.getXTenantId()) 75 | .execute(); 76 | } 77 | 78 | public List hash(HashParams hashParams) throws ApiException { 79 | 80 | if (hashParams.getAccessReason() == null) { 81 | throw new ApiException("Access reason is required"); 82 | } 83 | return this.cryptoApi.hashObjects( 84 | hashParams.getCollection(), 85 | hashParams.getHashObjectRequests()) 86 | .reason(hashParams.getAccessReason().getReason()) 87 | .adhocReason(hashParams.getAccessReason().getAdhocReason()) 88 | .customAudit(hashParams.getCustomAudit()) 89 | .reloadCache(hashParams.isReloadCache()) 90 | .execute(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/ObjectClient.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client; 2 | 3 | import com.piiano.vault.client.model.*; 4 | import com.piiano.vault.client.openapi.ApiClient; 5 | import com.piiano.vault.client.openapi.ApiException; 6 | import com.piiano.vault.client.openapi.ObjectsApi; 7 | import com.piiano.vault.client.openapi.model.*; 8 | 9 | import java.util.Map; 10 | 11 | /** 12 | * Client for the Object API. 13 | */ 14 | public class ObjectClient { 15 | 16 | private final ObjectsApi objectsApi; 17 | 18 | public ObjectClient(ApiClient apiClient) { 19 | this.objectsApi = new ObjectsApi(apiClient); 20 | } 21 | 22 | public ObjectsApi openapi() { 23 | return objectsApi; 24 | } 25 | 26 | public ObjectID addObject(AddObjectParams addObjectParams) throws ApiException { 27 | 28 | return this.objectsApi.addObject( 29 | addObjectParams.getCollection(), 30 | addObjectParams.getFields()) 31 | .reason(addObjectParams.getAccessReason().getReason()) 32 | .adhocReason(addObjectParams.getAccessReason().getAdhocReason()) 33 | .expirationSecs(addObjectParams.getExpirationSecs()) 34 | .customAudit(addObjectParams.getCustomAudit()) 35 | .reloadCache(addObjectParams.isReloadCache()) 36 | .xTenantId(addObjectParams.getXTenantId()) 37 | ._import(addObjectParams.getIsImport()) 38 | .exportKey(addObjectParams.getExportKey()) 39 | .execute(); 40 | } 41 | 42 | public BulkObjectResponse addObjects(AddObjectsParams addObjectsParams) throws ApiException { 43 | 44 | return this.objectsApi.addObjects( 45 | addObjectsParams.getCollection(), 46 | addObjectsParams.getFields()) 47 | .reason(addObjectsParams.getAccessReason().getReason()) 48 | .adhocReason(addObjectsParams.getAccessReason().getAdhocReason()) 49 | .expirationSecs(addObjectsParams.getExpirationSecs()) 50 | .customAudit(addObjectsParams.getCustomAudit()) 51 | .reloadCache(addObjectsParams.isReloadCache()) 52 | .xTenantId(addObjectsParams.getXTenantId()) 53 | ._import(addObjectsParams.getIsImport()) 54 | .exportKey(addObjectsParams.getExportKey()) 55 | .execute(); 56 | } 57 | 58 | public void deleteObject(DeleteObjectParams deleteObjectParams) throws ApiException { 59 | 60 | this.objectsApi.deleteObjectById( 61 | deleteObjectParams.getCollection(), 62 | deleteObjectParams.getObjectId()) 63 | .options(deleteObjectParams.getOptions()) 64 | .reason(deleteObjectParams.getAccessReason().getReason()) 65 | .adhocReason(deleteObjectParams.getAccessReason().getAdhocReason()) 66 | .customAudit(deleteObjectParams.getCustomAudit()) 67 | .reloadCache(deleteObjectParams.isReloadCache()) 68 | .xTenantId(deleteObjectParams.getXTenantId()) 69 | .execute(); 70 | } 71 | 72 | public BulkObjectResponse deleteObjects(DeleteObjectsParams deleteObjectsParams) throws ApiException { 73 | 74 | return this.objectsApi.deleteObjects( 75 | deleteObjectsParams.getCollection()) 76 | .objectID(deleteObjectsParams.getObjectIds()) 77 | .options(deleteObjectsParams.getOptions()) 78 | .reason(deleteObjectsParams.getAccessReason().getReason()) 79 | .adhocReason(deleteObjectsParams.getAccessReason().getAdhocReason()) 80 | .customAudit(deleteObjectsParams.getCustomAudit()) 81 | .reloadCache(deleteObjectsParams.isReloadCache()) 82 | .xTenantId(deleteObjectsParams.getXTenantId()) 83 | .execute(); 84 | } 85 | 86 | public Map getObject(GetObjectParams getObjectParams) throws ApiException { 87 | 88 | return this.objectsApi.getObjectById( 89 | getObjectParams.getCollection(), 90 | getObjectParams.getObjectId()) 91 | .props(getObjectParams.getProps()) 92 | .options(getObjectParams.getOptions()) 93 | .reason(getObjectParams.getAccessReason().getReason()) 94 | .adhocReason(getObjectParams.getAccessReason().getAdhocReason()) 95 | .customAudit(getObjectParams.getCustomAudit()) 96 | .reloadCache(getObjectParams.isReloadCache()) 97 | .xTenantId(getObjectParams.getXTenantId()) 98 | .execute(); 99 | } 100 | 101 | public ObjectFieldsPage listObjects(ListObjectsParams listObjectsParams) throws ApiException { 102 | 103 | return this.objectsApi.listObjects( 104 | listObjectsParams.getCollection()) 105 | .reason(listObjectsParams.getAccessReason().getReason()) 106 | .adhocReason(listObjectsParams.getAccessReason().getAdhocReason()) 107 | .ids(listObjectsParams.getObjectIds()) 108 | .props(listObjectsParams.getProps()) 109 | .cursor(listObjectsParams.getCursor()) 110 | .pageSize(listObjectsParams.getPageSize()) 111 | .options(listObjectsParams.getOptions()) 112 | .customAudit(listObjectsParams.getCustomAudit()) 113 | .reloadCache(listObjectsParams.isReloadCache()) 114 | .xTenantId(listObjectsParams.getXTenantId()) 115 | .xTransParam(listObjectsParams.getXTransParam()) 116 | .execute(); 117 | } 118 | 119 | public ObjectFieldsPage searchObjects(SearchObjectsParams searchObjectsParams) throws ApiException { 120 | 121 | return this.objectsApi.searchObjects( 122 | searchObjectsParams.getCollection(), 123 | searchObjectsParams.getQuery()) 124 | .reason(searchObjectsParams.getAccessReason().getReason()) 125 | .adhocReason(searchObjectsParams.getAccessReason().getAdhocReason()) 126 | .props(searchObjectsParams.getProps()) 127 | .cursor(searchObjectsParams.getCursor()) 128 | .pageSize(searchObjectsParams.getPageSize()) 129 | .options(searchObjectsParams.getOptions()) 130 | .customAudit(searchObjectsParams.getCustomAudit()) 131 | .reloadCache(searchObjectsParams.isReloadCache()) 132 | .xTenantId(searchObjectsParams.getXTenantId()) 133 | .xTransParam(searchObjectsParams.getXTransParam()) 134 | .execute(); 135 | } 136 | 137 | public void updateObject(UpdateObjectParams updateObjectParams) throws ApiException { 138 | 139 | this.objectsApi.updateObjectById( 140 | updateObjectParams.getCollection(), 141 | updateObjectParams.getObjectId(), 142 | updateObjectParams.getFields()) 143 | .reason(updateObjectParams.getAccessReason().getReason()) 144 | .adhocReason(updateObjectParams.getAccessReason().getAdhocReason()) 145 | .expirationSecs(updateObjectParams.getExpirationSecs()) 146 | .options(updateObjectParams.getOptions()) 147 | .customAudit(updateObjectParams.getCustomAudit()) 148 | .reloadCache(updateObjectParams.isReloadCache()) 149 | .xTenantId(updateObjectParams.getXTenantId()) 150 | ._import(updateObjectParams.getIsImport()) 151 | .exportKey(updateObjectParams.getExportKey()) 152 | .execute(); 153 | } 154 | 155 | public BulkObjectResponse updateObjects(UpdateObjectsParams updateObjectsParams) throws ApiException { 156 | 157 | return this.objectsApi.updateObjects( 158 | updateObjectsParams.getCollection()) 159 | .reason(updateObjectsParams.getAccessReason().getReason()) 160 | .adhocReason(updateObjectsParams.getAccessReason().getAdhocReason()) 161 | .requestBody(updateObjectsParams.getObjects()) 162 | .expirationSecs(updateObjectsParams.getExpirationSecs()) 163 | .options(updateObjectsParams.getOptions()) 164 | .customAudit(updateObjectsParams.getCustomAudit()) 165 | .reloadCache(updateObjectsParams.isReloadCache()) 166 | .xTenantId(updateObjectsParams.getXTenantId()) 167 | ._import(updateObjectsParams.getIsImport()) 168 | .exportKey(updateObjectsParams.getExportKey()) 169 | .execute(); 170 | } 171 | 172 | public Count getObjectsCount(CommonParams commonParams) throws ApiException { 173 | 174 | return this.objectsApi.getObjectsCount( 175 | commonParams.getCollection()) 176 | .reason(commonParams.getAccessReason().getReason()) 177 | .adhocReason(commonParams.getAccessReason().getAdhocReason()) 178 | .customAudit(commonParams.getCustomAudit()) 179 | .reloadCache(commonParams.isReloadCache()) 180 | .execute(); 181 | } 182 | } 183 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/TokenClient.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client; 2 | 3 | import com.piiano.vault.client.model.*; 4 | import com.piiano.vault.client.openapi.ApiClient; 5 | import com.piiano.vault.client.openapi.ApiException; 6 | import com.piiano.vault.client.openapi.TokensApi; 7 | import com.piiano.vault.client.openapi.model.*; 8 | 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * Client for the Token API. 14 | */ 15 | public class TokenClient { 16 | 17 | private final TokensApi tokensApi; 18 | 19 | public TokenClient(ApiClient apiClient) { 20 | this.tokensApi = new TokensApi(apiClient); 21 | } 22 | 23 | public TokensApi openapi() { 24 | return tokensApi; 25 | } 26 | 27 | public List tokenize(TokenizeParams tokenizeParams) throws ApiException { 28 | return this.tokensApi.tokenize( 29 | tokenizeParams.getCollection(), 30 | tokenizeParams.getTokenizeRequest()) 31 | .reason(tokenizeParams.getAccessReason().getReason()) 32 | .adhocReason(tokenizeParams.getAccessReason().getAdhocReason()) 33 | .expirationSecs(tokenizeParams.getExpirationSecs()) 34 | .customAudit(tokenizeParams.getCustomAudit()) 35 | .reloadCache(tokenizeParams.isReloadCache()) 36 | .xTenantId(tokenizeParams.getXTenantId()) 37 | .transactionId(tokenizeParams.getTransactionId()) 38 | .execute(); 39 | } 40 | 41 | public List detokenize(DetokenizeParams detokenizeParams) throws ApiException { 42 | return this.tokensApi.detokenize( 43 | detokenizeParams.getCollection()) 44 | .reason(detokenizeParams.getAccessReason().getReason()) 45 | .adhocReason(detokenizeParams.getAccessReason().getAdhocReason()) 46 | .tokenIds(detokenizeParams.getTokenQuery().getTokenIds()) 47 | .objectIds(detokenizeParams.getTokenQuery().getObjectIds()) 48 | .tags(detokenizeParams.getTokenQuery().getTags()) 49 | .props(detokenizeParams.getProps()) 50 | .options(detokenizeParams.getOptions()) 51 | .customAudit(detokenizeParams.getCustomAudit()) 52 | .reloadCache(detokenizeParams.isReloadCache()) 53 | .xTenantId(detokenizeParams.getXTenantId()) 54 | .execute(); 55 | } 56 | 57 | public List searchTokens(SearchTokensParams searchTokensParams) throws ApiException { 58 | QueryToken queryToken = new QueryToken(); 59 | queryToken.setTokenIds(searchTokensParams.getTokenQuery().getTokenIds()); 60 | queryToken.setObjectIds(searchTokensParams.getTokenQuery().getObjectIds()); 61 | queryToken.setTags(searchTokensParams.getTokenQuery().getTags()); 62 | 63 | return this.tokensApi.searchTokens( 64 | searchTokensParams.getCollection(), 65 | queryToken) 66 | .reason(searchTokensParams.getAccessReason().getReason()) 67 | .adhocReason(searchTokensParams.getAccessReason().getAdhocReason()) 68 | .options(searchTokensParams.getOptions()) 69 | .customAudit(searchTokensParams.getCustomAudit()) 70 | .reloadCache(searchTokensParams.isReloadCache()) 71 | .xTenantId(searchTokensParams.getXTenantId()) 72 | .execute(); 73 | } 74 | 75 | public void updateTokens(UpdateTokensParams updateTokensParams) throws ApiException { 76 | this.tokensApi.updateTokens( 77 | updateTokensParams.getCollection(), 78 | updateTokensParams.getUpdateTokenRequest()) 79 | .reason(updateTokensParams.getAccessReason().getReason()) 80 | .adhocReason(updateTokensParams.getAccessReason().getAdhocReason()) 81 | .tokenIds(updateTokensParams.getTokenQuery().getTokenIds()) 82 | .objectIds(updateTokensParams.getTokenQuery().getObjectIds()) 83 | .tags(updateTokensParams.getTokenQuery().getTags()) 84 | .expirationSecs(updateTokensParams.getExpirationSecs()) 85 | .customAudit(updateTokensParams.getCustomAudit()) 86 | .reloadCache(updateTokensParams.isReloadCache()) 87 | .xTenantId(updateTokensParams.getXTenantId()) 88 | .execute(); 89 | } 90 | 91 | public void deleteTokens(DeleteTokensParams deleteTokensParams) throws ApiException { 92 | this.tokensApi.deleteTokens( 93 | deleteTokensParams.getCollection()) 94 | .reason(deleteTokensParams.getAccessReason().getReason()) 95 | .adhocReason(deleteTokensParams.getAccessReason().getAdhocReason()) 96 | .tokenIds(deleteTokensParams.getTokenQuery().getTokenIds()) 97 | .objectIds(deleteTokensParams.getTokenQuery().getObjectIds()) 98 | .tags(deleteTokensParams.getTokenQuery().getTags()) 99 | .tenantId(deleteTokensParams.getTenantId()) 100 | .options(deleteTokensParams.getOptions()) 101 | .customAudit(deleteTokensParams.getCustomAudit()) 102 | .reloadCache(deleteTokensParams.isReloadCache()) 103 | .xTenantId(deleteTokensParams.getXTenantId()) 104 | .execute(); 105 | } 106 | 107 | public Map rotateTokens(RotateTokensParams rotateTokensParams) throws ApiException { 108 | return this.tokensApi.rotateTokens( 109 | rotateTokensParams.getTokenIds(), 110 | rotateTokensParams.getCollection()) 111 | .reason(rotateTokensParams.getAccessReason().getReason()) 112 | .adhocReason(rotateTokensParams.getAccessReason().getAdhocReason()) 113 | .customAudit(rotateTokensParams.getCustomAudit()) 114 | .reloadCache(rotateTokensParams.isReloadCache()) 115 | .xTenantId(rotateTokensParams.getXTenantId()) 116 | .execute(); 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/VaultClient.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client; 2 | 3 | import com.piiano.vault.client.openapi.ApiClient; 4 | import org.apache.commons.lang3.StringUtils; 5 | 6 | /** 7 | * Client for the Vault API. 8 | */ 9 | public class VaultClient { 10 | 11 | private final ObjectClient objectClient; 12 | private final TokenClient tokenClient; 13 | private final CryptoClient cryptoClient; 14 | 15 | public VaultClient(ApiClient apiClient) { 16 | this.objectClient = new ObjectClient(apiClient); 17 | this.tokenClient = new TokenClient(apiClient); 18 | this.cryptoClient = new CryptoClient(apiClient); 19 | } 20 | 21 | public ObjectClient objectClient() { 22 | return objectClient; 23 | } 24 | 25 | public TokenClient tokenClient() { 26 | return tokenClient; 27 | } 28 | 29 | public CryptoClient cryptoClient() { 30 | return cryptoClient; 31 | } 32 | 33 | public static ApiClient getPvaultClient() { 34 | String pvaultUrl = System.getenv("pvault_url"); 35 | if (StringUtils.isEmpty(pvaultUrl)) { 36 | pvaultUrl = "http://localhost:8123"; 37 | } 38 | 39 | String pvaultAuth = System.getenv("pvault_auth"); 40 | if (StringUtils.isEmpty(pvaultAuth)) { 41 | pvaultAuth = "pvaultauth"; 42 | } 43 | 44 | ApiClient pvaultClient = com.piiano.vault.client.openapi.Configuration.getDefaultApiClient(); 45 | pvaultClient.setBasePath(pvaultUrl); 46 | pvaultClient.setBearerToken(pvaultAuth); 47 | pvaultClient.addDefaultHeader("Content-Type", "application/json"); 48 | return pvaultClient; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/AccessReason.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Getter; 4 | 5 | /** 6 | * Available values for the access reason, for "Other" an ad-hoc reason can be provided. 7 | */ 8 | @Getter 9 | public enum AccessReason { 10 | 11 | AppFunctionality("AppFunctionality"), 12 | Analytics("Analytics"), 13 | Notifications("Notifications"), 14 | ThirdPartyMarketing("ThirdPartyMarketing"), 15 | Marketing("Marketing"), 16 | FraudPreventionSecurityAndCompliance("FraudPreventionSecurityAndCompliance"), 17 | AccountManagement("AccountManagement"), 18 | Maintenance("Maintenance"), 19 | DataSubjectRequest("DataSubjectRequest"), 20 | Other("Other") 21 | { 22 | public AccessReason adhocReason(String adhocReason) { 23 | this.adhocReason = adhocReason; 24 | return this; 25 | } 26 | 27 | @Override 28 | public String toString() { 29 | return "Other:" + this.adhocReason; 30 | } 31 | }; 32 | 33 | // Details of the access reason. The default is set when no access reason is provided and PVAULT_SERVICE_FORCE_ACCESS_REASON is false. (required) 34 | private final String reason; 35 | 36 | // An ad-hoc reason for accessing the Vault data. (optional) 37 | protected String adhocReason; 38 | 39 | 40 | AccessReason(String reason) { 41 | this.reason = reason; 42 | this.adhocReason = null; 43 | } 44 | 45 | public AccessReason adhocReason(String adhocReason) { 46 | if (Other == this) { 47 | return Other.adhocReason(adhocReason); 48 | } 49 | return this; 50 | } 51 | 52 | @Override 53 | public String toString() { 54 | return String.valueOf(reason); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/AddObjectParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.util.Map; 8 | 9 | @Data 10 | @SuperBuilder 11 | @EqualsAndHashCode(callSuper = true) 12 | public class AddObjectParams extends CommonParams { 13 | 14 | private Map fields; 15 | private String expirationSecs; 16 | private Boolean isImport; 17 | private String exportKey; 18 | } 19 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/AddObjectsParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | @Data 11 | @SuperBuilder 12 | @EqualsAndHashCode(callSuper = true) 13 | public class AddObjectsParams extends CommonParams { 14 | 15 | private List> fields; 16 | 17 | private String expirationSecs; 18 | 19 | private Boolean isImport; 20 | 21 | private String exportKey; 22 | } 23 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/CommonParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.SuperBuilder; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * Common parameters for the Vault Clients. 10 | */ 11 | @Data 12 | @SuperBuilder 13 | public class CommonParams { 14 | 15 | /** 16 | * collection The name of the collection containing the objects. 17 | */ 18 | private String collection; 19 | 20 | /** 21 | * accessReason Details of the reason for requesting the property. The default is set when no access reason is provided and PVAULT_SERVICE_FORCE_ACCESS_REASON is false. 22 | */ 23 | private AccessReason accessReason; 24 | 25 | /** 26 | * reloadCache Reloads the cache before the action. 27 | */ 28 | private boolean reloadCache; 29 | 30 | /** 31 | * customAudit 32 | */ 33 | private String customAudit; 34 | 35 | /** 36 | * xTenantId List of tenant IDs to enforce on the request. 37 | */ 38 | private List xTenantId; 39 | 40 | /** 41 | * transactionId The transaction ID to attach to the token. 42 | */ 43 | private String transactionId; 44 | } 45 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/DecryptParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import com.piiano.vault.client.openapi.model.DecryptionRequest; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import java.util.List; 9 | import java.util.Set; 10 | 11 | /** 12 | * Parameters for 'decrypt' API. 13 | */ 14 | @Data 15 | @SuperBuilder 16 | @EqualsAndHashCode(callSuper = true) 17 | public class DecryptParams extends CommonParams { 18 | 19 | private List decryptionRequests; 20 | 21 | private Set options; 22 | } 23 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/DeleteObjectParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.util.Set; 8 | import java.util.UUID; 9 | 10 | @Data 11 | @SuperBuilder 12 | @EqualsAndHashCode(callSuper = true) 13 | public class DeleteObjectParams extends CommonParams { 14 | 15 | private UUID objectId; 16 | 17 | private Set options; 18 | } 19 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/DeleteObjectsParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import com.piiano.vault.client.openapi.model.ObjectID; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import java.util.List; 9 | import java.util.Set; 10 | 11 | /** 12 | * Parameters for 'deleteObjects' API. 13 | */ 14 | @Data 15 | @SuperBuilder 16 | @EqualsAndHashCode(callSuper = true) 17 | public class DeleteObjectsParams extends CommonParams { 18 | 19 | private List objectIds; 20 | 21 | private Set options; 22 | } 23 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/DeleteTokensParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.util.List; 8 | import java.util.Set; 9 | 10 | /** 11 | * Parameters for 'deleteTokens' API. 12 | */ 13 | @Data 14 | @SuperBuilder 15 | @EqualsAndHashCode(callSuper = true) 16 | public class DeleteTokensParams extends CommonParams { 17 | 18 | private TokenQuery tokenQuery; 19 | 20 | private List props; 21 | 22 | private Set options; 23 | 24 | private String tenantId; 25 | } 26 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/DetokenizeParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.util.List; 8 | import java.util.Set; 9 | 10 | /** 11 | * Parameters for 'detokenize' API. 12 | */ 13 | @Data 14 | @SuperBuilder 15 | @EqualsAndHashCode(callSuper = true) 16 | public class DetokenizeParams extends CommonParams { 17 | 18 | private TokenQuery tokenQuery; 19 | 20 | private List props; 21 | 22 | private Set options; 23 | } 24 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/EncryptParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import com.piiano.vault.client.openapi.model.EncryptionRequest; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Parameters for 'encrypt' API. 12 | */ 13 | @Data 14 | @SuperBuilder 15 | @EqualsAndHashCode(callSuper = true) 16 | public class EncryptParams extends CommonParams { 17 | 18 | private List encryptionRequest; 19 | 20 | private String expirationSecs; 21 | } 22 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/GetObjectParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.util.List; 8 | import java.util.Set; 9 | import java.util.UUID; 10 | 11 | @Data 12 | @SuperBuilder 13 | @EqualsAndHashCode(callSuper = true) 14 | public class GetObjectParams extends CommonParams { 15 | 16 | private UUID objectId; 17 | 18 | private List props; 19 | 20 | private Set options; 21 | } 22 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/HashParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import com.piiano.vault.client.openapi.model.HashObjectRequest; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Parameters for 'hashObjects' API. 12 | */ 13 | @Data 14 | @SuperBuilder 15 | @EqualsAndHashCode(callSuper = true) 16 | public class HashParams extends CommonParams { 17 | 18 | private List hashObjectRequests; 19 | } 20 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/ListObjectsParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.util.List; 8 | import java.util.Set; 9 | import java.util.UUID; 10 | 11 | @Data 12 | @SuperBuilder 13 | @EqualsAndHashCode(callSuper = true) 14 | public class ListObjectsParams extends CommonParams { 15 | 16 | private List objectIds; 17 | 18 | private List props; 19 | 20 | private Set options; 21 | 22 | private String cursor; 23 | 24 | private Integer pageSize; 25 | 26 | private String xTransParam; 27 | } 28 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/RotateTokensParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * Parameters for 'rotateTokens' API. 11 | */ 12 | @Data 13 | @SuperBuilder 14 | @EqualsAndHashCode(callSuper = true) 15 | public class RotateTokensParams extends CommonParams { 16 | 17 | List tokenIds; 18 | } 19 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/SearchObjectsParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import com.piiano.vault.client.openapi.model.Query; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import java.util.List; 9 | import java.util.Set; 10 | import java.util.UUID; 11 | 12 | @Data 13 | @SuperBuilder 14 | @EqualsAndHashCode(callSuper = true) 15 | public class SearchObjectsParams extends CommonParams { 16 | 17 | private Query query; 18 | 19 | private List props; 20 | 21 | private Set options; 22 | 23 | private String cursor; 24 | 25 | private Integer pageSize; 26 | 27 | private String xTransParam; 28 | } 29 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/SearchTokensParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.util.Set; 8 | 9 | /** 10 | * Parameters for 'searchTokens' API. 11 | */ 12 | @Data 13 | @SuperBuilder 14 | @EqualsAndHashCode(callSuper = true) 15 | public class SearchTokensParams extends CommonParams { 16 | 17 | private TokenQuery tokenQuery; 18 | 19 | private Set options; 20 | } 21 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/TokenQuery.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.experimental.SuperBuilder; 5 | 6 | import java.util.List; 7 | import java.util.UUID; 8 | 9 | @Data 10 | @SuperBuilder 11 | public class TokenQuery { 12 | 13 | private List tokenIds; 14 | 15 | private List objectIds; 16 | 17 | private List tags; 18 | } 19 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/TokenizeParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import com.piiano.vault.client.openapi.model.TokenizeRequest; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import java.util.List; 9 | 10 | /** 11 | * Parameters for 'tokenize' API. 12 | */ 13 | @Data 14 | @SuperBuilder 15 | @EqualsAndHashCode(callSuper = true) 16 | public class TokenizeParams extends CommonParams { 17 | 18 | private List tokenizeRequest; 19 | 20 | private String expirationSecs; 21 | } 22 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/UpdateEncryptedParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import com.piiano.vault.client.openapi.model.UpdateEncryptionRequest; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import java.util.List; 9 | import java.util.Set; 10 | 11 | /** 12 | * Parameters for 'updateEncrypted' API. 13 | */ 14 | @Data 15 | @SuperBuilder 16 | @EqualsAndHashCode(callSuper = true) 17 | public class UpdateEncryptedParams extends CommonParams { 18 | 19 | private List updateEncryptionRequests; 20 | 21 | private Set options; 22 | 23 | private String expirationSecs; 24 | } 25 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/UpdateObjectParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | import java.util.UUID; 11 | 12 | @Data 13 | @SuperBuilder 14 | @EqualsAndHashCode(callSuper = true) 15 | public class UpdateObjectParams extends CommonParams { 16 | 17 | private UUID objectId; 18 | 19 | private Map fields; 20 | 21 | private Set options; 22 | 23 | private String expirationSecs; 24 | 25 | private Boolean isImport; 26 | 27 | private String exportKey; 28 | } 29 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/UpdateObjectsParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import lombok.Data; 4 | import lombok.EqualsAndHashCode; 5 | import lombok.experimental.SuperBuilder; 6 | 7 | import java.util.List; 8 | import java.util.Map; 9 | import java.util.Set; 10 | 11 | @Data 12 | @SuperBuilder 13 | @EqualsAndHashCode(callSuper = true) 14 | public class UpdateObjectsParams extends CommonParams { 15 | 16 | private List> objects; 17 | 18 | private Set options; 19 | 20 | private String expirationSecs; 21 | 22 | private Boolean isImport; 23 | 24 | private String exportKey; 25 | } 26 | -------------------------------------------------------------------------------- /sdk/client/src/main/java/com/piiano/vault/client/model/UpdateTokensParams.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client.model; 2 | 3 | import com.piiano.vault.client.openapi.model.UpdateTokenRequest; 4 | import lombok.Data; 5 | import lombok.EqualsAndHashCode; 6 | import lombok.experimental.SuperBuilder; 7 | 8 | import java.util.Set; 9 | 10 | /** 11 | * Parameters for 'updateTokens' API. 12 | */ 13 | @Data 14 | @SuperBuilder 15 | @EqualsAndHashCode(callSuper = true) 16 | public class UpdateTokensParams extends CommonParams { 17 | 18 | private UpdateTokenRequest updateTokenRequest; 19 | 20 | private TokenQuery tokenQuery; 21 | 22 | private Set options; 23 | 24 | private String expirationSecs; 25 | } 26 | -------------------------------------------------------------------------------- /sdk/client/src/test/java/com/piiano/vault/client/CollectionSetup.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client; 2 | 3 | import com.piiano.vault.client.openapi.ApiClient; 4 | import com.piiano.vault.client.openapi.ApiException; 5 | import com.piiano.vault.client.openapi.CollectionsApi; 6 | import com.piiano.vault.client.openapi.Configuration; 7 | import com.piiano.vault.client.openapi.model.Collection; 8 | import com.piiano.vault.client.openapi.model.Property; 9 | 10 | public class CollectionSetup { 11 | 12 | public static final String collectionName = "users_test"; 13 | 14 | public static void setUp() throws ApiException { 15 | addCollection(); 16 | } 17 | 18 | public static void tearDown() { 19 | deleteCollectionIfExists(); 20 | } 21 | 22 | private static Collection addCollection() throws ApiException { 23 | 24 | ApiClient pvaultClient = getApiClient(); 25 | CollectionsApi collectionsApi = new CollectionsApi(pvaultClient); 26 | 27 | deleteCollectionIfExists(); 28 | 29 | Collection collection = createCollection(); 30 | return collectionsApi.addCollection(collection).format("json").execute(); 31 | } 32 | 33 | private static void deleteCollectionIfExists() { 34 | ApiClient pvaultClient = getApiClient(); 35 | CollectionsApi collectionsApi = new CollectionsApi(pvaultClient); 36 | 37 | try { 38 | collectionsApi.deleteCollection(collectionName).execute(); 39 | } catch (ApiException e) { 40 | // Collection not found - do nothing. 41 | } 42 | } 43 | 44 | public static Collection createCollection() { 45 | return new Collection() 46 | .name(collectionName) 47 | .type(Collection.TypeEnum.PERSONS) 48 | .addPropertiesItem( 49 | new Property().name("name").dataTypeName("NAME").description("Name") 50 | .isEncrypted(true) 51 | ).addPropertiesItem( 52 | new Property().name("phone_number").dataTypeName("PHONE_NUMBER").description("Phone number") 53 | .isEncrypted(true).isNullable(true) 54 | ); 55 | } 56 | 57 | private static ApiClient getApiClient() { 58 | // Create configuration, bearer auth and client API 59 | ApiClient pvaultClient = Configuration.getDefaultApiClient(); 60 | pvaultClient.setBasePath("http://localhost:8123"); 61 | pvaultClient.setBearerToken("pvaultauth"); 62 | pvaultClient.addDefaultHeader("Content-Type", "application/json"); 63 | return pvaultClient; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /sdk/client/src/test/java/com/piiano/vault/client/CryptoClientTest.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.common.collect.ImmutableMap; 5 | import com.piiano.vault.client.model.AccessReason; 6 | import com.piiano.vault.client.model.EncryptParams; 7 | import com.piiano.vault.client.openapi.ApiClient; 8 | import com.piiano.vault.client.openapi.ApiException; 9 | import com.piiano.vault.client.openapi.model.EncryptedValue; 10 | import com.piiano.vault.client.openapi.model.EncryptionRequest; 11 | import com.piiano.vault.client.openapi.model.EncryptionType; 12 | import com.piiano.vault.client.openapi.model.InputObject; 13 | import org.junit.jupiter.api.AfterEach; 14 | import org.junit.jupiter.api.BeforeEach; 15 | import org.junit.jupiter.api.Test; 16 | 17 | import java.util.List; 18 | 19 | import static com.piiano.vault.client.CollectionSetup.collectionName; 20 | import static com.piiano.vault.client.DefaultClient.getDefaultClient; 21 | import static org.junit.jupiter.api.Assertions.assertEquals; 22 | import static org.junit.jupiter.api.Assertions.assertNotNull; 23 | 24 | public class CryptoClientTest { 25 | 26 | private final ApiClient apiClient = getDefaultClient(); 27 | 28 | private final CryptoClient cryptoClient = new CryptoClient(apiClient); 29 | 30 | @BeforeEach 31 | public void beforeEach() throws ApiException { 32 | CollectionSetup.setUp(); 33 | } 34 | 35 | @AfterEach 36 | public void afterEach() { 37 | CollectionSetup.tearDown(); 38 | } 39 | 40 | @Test 41 | public void encryptionTest() throws ApiException { 42 | EncryptionRequest request = new EncryptionRequest() 43 | .type(EncryptionType.DETERMINISTIC) 44 | ._object(new InputObject().fields(ImmutableMap.of("name", "John"))); 45 | 46 | List result = cryptoClient.encrypt( 47 | EncryptParams.builder() 48 | .collection(collectionName) 49 | .accessReason(AccessReason.AppFunctionality) 50 | .encryptionRequest(ImmutableList.of(request)) 51 | .build()); 52 | assertEquals(1, result.size()); 53 | assertNotNull(result.get(0).getCiphertext()); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /sdk/client/src/test/java/com/piiano/vault/client/DefaultClient.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client; 2 | 3 | import com.piiano.vault.client.openapi.ApiClient; 4 | import com.piiano.vault.client.openapi.Configuration; 5 | 6 | public class DefaultClient { 7 | 8 | public static ApiClient getDefaultClient() { 9 | 10 | // Create configuration, bearer auth and client API 11 | ApiClient apiClient = Configuration.getDefaultApiClient(); 12 | apiClient.setBasePath("http://localhost:8123"); 13 | apiClient.setBearerToken("pvaultauth"); 14 | apiClient.addDefaultHeader("Content-Type", "application/json"); 15 | 16 | return apiClient; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /sdk/client/src/test/java/com/piiano/vault/client/ObjectClientTest.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.common.collect.ImmutableMap; 5 | import com.piiano.vault.client.model.*; 6 | import com.piiano.vault.client.openapi.ApiClient; 7 | import com.piiano.vault.client.openapi.ApiException; 8 | import com.piiano.vault.client.openapi.model.*; 9 | import org.junit.jupiter.api.AfterEach; 10 | import org.junit.jupiter.api.BeforeEach; 11 | import org.junit.jupiter.api.Test; 12 | 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | import static com.piiano.vault.client.CollectionSetup.collectionName; 17 | import static com.piiano.vault.client.DefaultClient.getDefaultClient; 18 | import static org.junit.jupiter.api.Assertions.assertEquals; 19 | import static org.junit.jupiter.api.Assertions.assertNotNull; 20 | 21 | public class ObjectClientTest { 22 | 23 | private final ApiClient apiClient = getDefaultClient(); 24 | 25 | private final ObjectClient objectClient = new ObjectClient(apiClient); 26 | 27 | @BeforeEach 28 | public void beforeEach() throws ApiException { 29 | CollectionSetup.setUp(); 30 | } 31 | 32 | @AfterEach 33 | public void afterEach() { 34 | CollectionSetup.tearDown(); 35 | } 36 | 37 | @Test 38 | public void objectOperationsTest() throws ApiException { 39 | 40 | // Add an object 41 | String propName = "name"; 42 | String name = "John"; 43 | Map fields = ImmutableMap.of(propName, name); 44 | 45 | ObjectID objectID = objectClient.addObject( 46 | AddObjectParams.builder() 47 | .collection(collectionName) 48 | .fields(fields) 49 | .accessReason(AccessReason.AppFunctionality) 50 | .build()); 51 | assertNotNull(objectID); 52 | assertNotNull(objectID.getId()); 53 | 54 | // Get the object 55 | Map objectFields = objectClient.getObject( 56 | GetObjectParams.builder() 57 | .collection(collectionName) 58 | .objectId(objectID.getId()) 59 | .props(ImmutableList.of(propName)) 60 | .accessReason(AccessReason.AppFunctionality) 61 | .build()); 62 | assertEquals(1, objectFields.size()); 63 | assertEquals(name, objectFields.get(propName)); 64 | 65 | // Update the object 66 | String newName = "Jane"; 67 | objectClient.updateObject( 68 | UpdateObjectParams.builder() 69 | .collection(collectionName) 70 | .objectId(objectID.getId()) 71 | .fields(ImmutableMap.of(propName, newName)) 72 | .accessReason(AccessReason.AppFunctionality) 73 | .build()); 74 | 75 | // get the object again and validate the updated value 76 | objectFields = objectClient.getObject( 77 | GetObjectParams.builder() 78 | .collection(collectionName) 79 | .objectId(objectID.getId()) 80 | .props(ImmutableList.of(propName)) 81 | .accessReason(AccessReason.AppFunctionality) 82 | .build()); 83 | assertEquals(1, objectFields.size()); 84 | assertEquals(newName, objectFields.get(propName)); 85 | 86 | // Search the object 87 | ObjectFieldsPage objectsPage = objectClient.searchObjects( 88 | SearchObjectsParams.builder() 89 | .collection(collectionName) 90 | .query(new Query().match(ImmutableMap.of("id", objectID.getId()))) 91 | .props(ImmutableList.of(propName)) 92 | .accessReason(AccessReason.AppFunctionality) 93 | .build()); 94 | assertEquals(1, objectsPage.getResults().size()); 95 | assertEquals(newName, objectsPage.getResults().get(0).get(propName)); 96 | 97 | objectClient.deleteObject( 98 | DeleteObjectParams.builder() 99 | .collection(collectionName) 100 | .objectId(objectID.getId()) 101 | .accessReason(AccessReason.AppFunctionality) 102 | .build()); 103 | 104 | // Search the token again and verify it is deleted 105 | objectsPage = objectClient.searchObjects( 106 | SearchObjectsParams.builder() 107 | .collection(collectionName) 108 | .query(new Query().match(ImmutableMap.of("id", objectID.getId()))) 109 | .props(ImmutableList.of(propName)) 110 | .accessReason(AccessReason.AppFunctionality) 111 | .build()); 112 | 113 | assertEquals(0, objectsPage.getResults().size()); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /sdk/client/src/test/java/com/piiano/vault/client/TokenClientTest.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.common.collect.ImmutableMap; 5 | import com.piiano.vault.client.model.*; 6 | import com.piiano.vault.client.openapi.ApiClient; 7 | import com.piiano.vault.client.openapi.ApiException; 8 | import com.piiano.vault.client.openapi.model.*; 9 | import org.junit.jupiter.api.AfterEach; 10 | import org.junit.jupiter.api.BeforeEach; 11 | import org.junit.jupiter.api.Test; 12 | 13 | import java.util.List; 14 | 15 | import static com.piiano.vault.client.CollectionSetup.collectionName; 16 | import static com.piiano.vault.client.DefaultClient.getDefaultClient; 17 | import static org.junit.jupiter.api.Assertions.assertEquals; 18 | import static org.junit.jupiter.api.Assertions.assertNotNull; 19 | 20 | public class TokenClientTest { 21 | 22 | private final ApiClient apiClient = getDefaultClient(); 23 | 24 | private final TokenClient tokenClient = new TokenClient(apiClient); 25 | 26 | @BeforeEach 27 | public void beforeEach() throws ApiException { 28 | CollectionSetup.setUp(); 29 | } 30 | 31 | @AfterEach 32 | public void afterEach() { 33 | CollectionSetup.tearDown(); 34 | } 35 | 36 | @Test 37 | public void tokenOperationsTest() throws ApiException { 38 | 39 | // Tokenize 40 | String propName = "name"; 41 | String name = "John"; 42 | TokenizeRequest request = new TokenizeRequest() 43 | .type(TokenType.RANDOMIZED) 44 | ._object(new InputObject().fields(ImmutableMap.of(propName, name))); 45 | 46 | List result = tokenClient.tokenize( 47 | TokenizeParams.builder() 48 | .collection(collectionName) 49 | .accessReason(AccessReason.AppFunctionality) 50 | .tokenizeRequest(ImmutableList.of(request)) 51 | .build()); 52 | assertEquals(1, result.size()); 53 | String tokenId = result.get(0).getTokenId(); 54 | assertNotNull(tokenId); 55 | 56 | // Detokenize 57 | TokenQuery tokenQuery = TokenQuery.builder().tokenIds(ImmutableList.of(tokenId)).build(); 58 | List detokenized = tokenClient.detokenize( 59 | DetokenizeParams.builder() 60 | .collection(collectionName) 61 | .accessReason(AccessReason.AppFunctionality) 62 | .tokenQuery(tokenQuery) 63 | .build()); 64 | 65 | assertEquals(1, detokenized.size()); 66 | assertEquals(name, detokenized.get(0).getFields().get(propName)); 67 | 68 | // Update Token 69 | String newName = "Jane"; 70 | UpdateTokenRequest updateTokenRequest = new UpdateTokenRequest(); 71 | updateTokenRequest._object(new InputObject().fields(ImmutableMap.of(propName, newName))); 72 | 73 | tokenClient.updateTokens( 74 | UpdateTokensParams.builder() 75 | .collection(collectionName) 76 | .accessReason(AccessReason.AppFunctionality) 77 | .tokenQuery(tokenQuery) 78 | .updateTokenRequest(updateTokenRequest) 79 | .build()); 80 | 81 | // Detokenize again and validate the updated value 82 | detokenized = tokenClient.detokenize( 83 | DetokenizeParams.builder() 84 | .collection(collectionName) 85 | .accessReason(AccessReason.AppFunctionality) 86 | .tokenQuery(tokenQuery) 87 | .build()); 88 | 89 | assertEquals(1, detokenized.size()); 90 | assertEquals(newName, detokenized.get(0).getFields().get(propName)); 91 | 92 | // Search the token 93 | List tokenMetadata = tokenClient.searchTokens( 94 | SearchTokensParams.builder() 95 | .collection(collectionName) 96 | .accessReason(AccessReason.AppFunctionality) 97 | .tokenQuery(tokenQuery) 98 | .build()); 99 | 100 | assertEquals(1, tokenMetadata.size()); 101 | assertEquals(TokenType.RANDOMIZED, tokenMetadata.get(0).getType()); 102 | 103 | tokenClient.deleteTokens( 104 | DeleteTokensParams.builder() 105 | .collection(collectionName) 106 | .accessReason(AccessReason.AppFunctionality) 107 | .tokenQuery(tokenQuery) 108 | .build()); 109 | 110 | // Search the token again and verify it is deleted 111 | tokenMetadata = tokenClient.searchTokens( 112 | SearchTokensParams.builder() 113 | .collection(collectionName) 114 | .accessReason(AccessReason.AppFunctionality) 115 | .tokenQuery(tokenQuery) 116 | .build()); 117 | assertEquals(0, tokenMetadata.size()); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /sdk/client/src/test/java/com/piiano/vault/client/VaultClientTest.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.client; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.common.collect.ImmutableMap; 5 | import com.piiano.vault.client.model.*; 6 | import com.piiano.vault.client.openapi.ApiClient; 7 | import com.piiano.vault.client.openapi.ApiException; 8 | import com.piiano.vault.client.openapi.model.*; 9 | import org.junit.jupiter.api.AfterEach; 10 | import org.junit.jupiter.api.BeforeEach; 11 | import org.junit.jupiter.api.Test; 12 | 13 | import java.util.List; 14 | import java.util.Map; 15 | 16 | import static com.piiano.vault.client.CollectionSetup.collectionName; 17 | import static com.piiano.vault.client.DefaultClient.getDefaultClient; 18 | import static org.junit.jupiter.api.Assertions.assertEquals; 19 | import static org.junit.jupiter.api.Assertions.assertNotNull; 20 | 21 | public class VaultClientTest { 22 | 23 | private final ApiClient apiClient = getDefaultClient(); 24 | 25 | private final VaultClient vaultClient = new VaultClient(apiClient); 26 | 27 | @BeforeEach 28 | public void beforeEach() throws ApiException { 29 | CollectionSetup.setUp(); 30 | } 31 | 32 | @AfterEach 33 | public void afterEach() { 34 | CollectionSetup.tearDown(); 35 | } 36 | 37 | @Test 38 | public void objectOperationsTest() throws ApiException { 39 | 40 | // Add an object 41 | String propName = "name"; 42 | String name = "John"; 43 | Map fields = ImmutableMap.of(propName, name); 44 | 45 | ObjectID objectID = vaultClient.objectClient().addObject( 46 | AddObjectParams.builder() 47 | .collection(collectionName) 48 | .fields(fields) 49 | .accessReason(AccessReason.AppFunctionality) 50 | .build()); 51 | assertNotNull(objectID); 52 | assertNotNull(objectID.getId()); 53 | 54 | // Get the object 55 | Map objectFields = vaultClient.objectClient().getObject( 56 | GetObjectParams.builder() 57 | .collection(collectionName) 58 | .objectId(objectID.getId()) 59 | .props(ImmutableList.of(propName)) 60 | .accessReason(AccessReason.AppFunctionality) 61 | .build()); 62 | assertEquals(1, objectFields.size()); 63 | assertEquals(name, objectFields.get(propName)); 64 | 65 | // Update the object 66 | String newName = "Jane"; 67 | vaultClient.objectClient().updateObject( 68 | UpdateObjectParams.builder() 69 | .collection(collectionName) 70 | .objectId(objectID.getId()) 71 | .fields(ImmutableMap.of(propName, newName)) 72 | .accessReason(AccessReason.AppFunctionality) 73 | .build()); 74 | 75 | // get the object again and validate the updated value 76 | objectFields = vaultClient.objectClient().getObject( 77 | GetObjectParams.builder() 78 | .collection(collectionName) 79 | .objectId(objectID.getId()) 80 | .props(ImmutableList.of(propName)) 81 | .accessReason(AccessReason.AppFunctionality) 82 | .build()); 83 | assertEquals(1, objectFields.size()); 84 | assertEquals(newName, objectFields.get(propName)); 85 | 86 | // Search the object 87 | ObjectFieldsPage objectsPage = vaultClient.objectClient().searchObjects( 88 | SearchObjectsParams.builder() 89 | .collection(collectionName) 90 | .query(new Query().match(ImmutableMap.of("id", objectID.getId()))) 91 | .props(ImmutableList.of(propName)) 92 | .accessReason(AccessReason.AppFunctionality) 93 | .build()); 94 | assertEquals(1, objectsPage.getResults().size()); 95 | assertEquals(newName, objectsPage.getResults().get(0).get(propName)); 96 | 97 | vaultClient.objectClient().deleteObject( 98 | DeleteObjectParams.builder() 99 | .collection(collectionName) 100 | .objectId(objectID.getId()) 101 | .accessReason(AccessReason.AppFunctionality) 102 | .build()); 103 | 104 | // Search the token again and verify it is deleted 105 | objectsPage = vaultClient.objectClient().searchObjects( 106 | SearchObjectsParams.builder() 107 | .collection(collectionName) 108 | .query(new Query().match(ImmutableMap.of("id", objectID.getId()))) 109 | .props(ImmutableList.of(propName)) 110 | .accessReason(AccessReason.AppFunctionality) 111 | .build()); 112 | 113 | assertEquals(0, objectsPage.getResults().size()); 114 | } 115 | 116 | 117 | @Test 118 | public void tokenizeTest() throws ApiException { 119 | TokenizeRequest request = new TokenizeRequest() 120 | .type(TokenType.DETERMINISTIC) 121 | ._object(new InputObject().fields(ImmutableMap.of("name", "John"))); 122 | 123 | List result = vaultClient.tokenClient().tokenize( 124 | TokenizeParams.builder() 125 | .collection(collectionName) 126 | .accessReason(AccessReason.AppFunctionality) 127 | .tokenizeRequest(ImmutableList.of(request)) 128 | .build()); 129 | assertEquals(1, result.size()); 130 | assertNotNull(result.get(0).getTokenId()); 131 | } 132 | 133 | @Test 134 | public void encryptionTest() throws ApiException { 135 | EncryptionRequest request = new EncryptionRequest() 136 | .type(EncryptionType.DETERMINISTIC) 137 | ._object(new InputObject().fields(ImmutableMap.of("name", "John"))); 138 | 139 | List result = vaultClient.cryptoClient().encrypt( 140 | EncryptParams.builder() 141 | .collection(collectionName) 142 | .accessReason(AccessReason.AppFunctionality) 143 | .encryptionRequest(ImmutableList.of(request)) 144 | .build()); 145 | assertEquals(1, result.size()); 146 | assertNotNull(result.get(0).getCiphertext()); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /sdk/config.yaml: -------------------------------------------------------------------------------- 1 | groupId: "com.piiano.vault" 2 | artifactId: "openapi" 3 | artifactVersion: "1.3.8" 4 | artifactDescription: "Generated client for the open API of Piiano vault" 5 | artifactUrl: "https://piiano.com/docs/api" 6 | apiPackage: "com.piiano.vault.client.openapi" 7 | modelPackage: "com.piiano.vault.client.openapi.model" 8 | invokerPackage: "com.piiano.vault.client.openapi" 9 | booleanGetterPrefix: "is" 10 | scmConnection: "scm:git:git@github.com/piiano/vault-java.git" 11 | scmDeveloperConnection: "scm:git:git@github.com/piiano/vault-java.git" 12 | scmUrl: "https://github.com/piiano/vault-java" 13 | licenseName: "MIT License" 14 | licenseUrl: "https://github.com/piiano/vault-java/blob/main/LICENSE" 15 | developerName: "Piiano vault-java contributors" 16 | developerEmail: "info@piiano.com" 17 | developerOrganization: "Piiano" 18 | developerOrganizationUrl: "https://piiano.com/" 19 | -------------------------------------------------------------------------------- /sdk/hibernate-encryption/README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | 6 | Piiano Vault 7 | 8 | 9 |

10 | 11 | # Piiano vault Hibernate encryption 12 | 13 | This package is compatible with Vault 1.14.0 14 | 15 | ## Compiling 16 | 17 | Run: `mvn clean install -DskipTests` 18 | 19 | ## Testing 20 | 21 | You will need to start Vault first. It is recommended to run testing from the Makefile in the [parent folder](./..). 22 | 23 | ### Vault ORM Annotations 24 | 25 | The hibernate-encryption jar contains the following annotations that you can use to integrate your entities seamlessly with Vault: 26 | - `@Type(type = "Encrypted")` - marks a field as encrypted. 27 | The field will be encrypted when persisted to the DB and decrypted when retrieved from the DB. 28 | You can optionally specify the name of the collection to use for encryption like so: 29 | `@Type(type = "Encrypted", parameters = {@Parameter(name = COLLECTION, value = "customers")})` 30 | If the collection name is not specified, the name of the Table specified in the `@Table` annotation will be used. 31 | - `@Transformation` - marks a field as a transformation of an encrypted property. 32 | The field will be automatically be decrypted and transformed by Vault when retrieved from the DB. 33 | You must specify the name of the encrypted property whose value will be transformed and the transformer to apply like so: 34 | `@Transformation(property = "email", transformer = "mask")` 35 | This will decrypt the encrypted value of the `email` property and apply the `mask` transformer to it. 36 | Note: You must also apply the `@Transient` annotation to the field so that it is not persisted to the DB. 37 | 38 | In order to use the `@Transformation` annotation, you must inject the `TransformerInterceptor` bean into your application context. 39 | This can be done by adding the following to your Spring configuration: 40 | 41 | ```java 42 | @Configuration 43 | @ComponentScan(" com.piiano.vault.orm.encryption") 44 | public class InterceptorConfig { 45 | @Bean 46 | public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(TransformationInterceptor interceptor) { 47 | return props -> props.put("hibernate.session_factory.interceptor", interceptor); 48 | } 49 | } 50 | ``` 51 | 52 | `TransformerInterceptor` intercepts the loading of all entities from the DB and decrypts and transforms the fields marked with the `@Transformation` annotation. 53 | It is not required if you are not using the `@Transformation` annotation in any field. 54 | -------------------------------------------------------------------------------- /sdk/hibernate-encryption/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.piiano.vault 7 | hibernate-encryption 8 | 1.3.8 9 | ${project.groupId}:${project.artifactId} 10 | Piiano hibernate encryption 11 | https://github.com/piiano/vault-java/tree/main/sdk/hibernate-encryption 12 | jar 13 | 14 | 15 | 8 16 | ${java.version} 17 | ${java.version} 18 | 19 | 1.18.34 20 | 32.1.3-jre 21 | 5.3.20 22 | 5.6.15.Final 23 | 4.13.2 24 | 5.10.0 25 | 26 | 27 | 28 | scm:git:git@github.com/piiano/vault-java.git 29 | scm:git:git@github.com/piiano/vault-java.git 30 | https://github.com/piiano/vault-java 31 | 32 | 33 | 34 | 35 | MIT License 36 | https://github.com/piiano/vault-java/blob/main/LICENSE 37 | repo 38 | 39 | 40 | 41 | 42 | 43 | Piiano vault-java contributors 44 | info@piiano.com 45 | Piiano 46 | https://piiano.com/ 47 | 48 | 49 | 50 | 51 | 52 | com.piiano.vault 53 | client 54 | ${project.version} 55 | 56 | 57 | org.projectlombok 58 | lombok 59 | ${lombok.version} 60 | provided 61 | 62 | 63 | com.google.guava 64 | guava 65 | ${guava.version} 66 | 67 | 68 | org.springframework 69 | spring-context 70 | ${spring-context.version} 71 | compile 72 | 73 | 74 | org.hibernate 75 | hibernate-core 76 | ${hibernate-core.version} 77 | compile 78 | 79 | 80 | 81 | 82 | 83 | ossrh 84 | https://s01.oss.sonatype.org/content/repositories/snapshots 85 | 86 | 87 | 88 | 89 | 90 | 91 | org.sonatype.plugins 92 | nexus-staging-maven-plugin 93 | 1.6.13 94 | true 95 | 96 | ossrh 97 | https://s01.oss.sonatype.org/ 98 | true 99 | 100 | 101 | 102 | org.apache.maven.plugins 103 | maven-source-plugin 104 | 3.3.1 105 | 106 | 107 | attach-sources 108 | 109 | jar-no-fork 110 | 111 | 112 | 113 | 114 | 115 | org.apache.maven.plugins 116 | maven-javadoc-plugin 117 | 3.11.1 118 | 119 | 120 | attach-javadocs 121 | 122 | jar 123 | 124 | 125 | 126 | 127 | none 128 | 129 | 130 | http.response.details 131 | a 132 | Http Response Details: 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | sign-artifacts 143 | 144 | 145 | 146 | org.apache.maven.plugins 147 | maven-gpg-plugin 148 | 3.2.7 149 | 150 | 151 | sign-artifacts 152 | verify 153 | 154 | sign 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | -------------------------------------------------------------------------------- /sdk/hibernate-encryption/src/main/java/com/piiano/vault/orm/encryption/Encrypted.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.orm.encryption; 2 | 3 | import com.piiano.vault.client.openapi.model.EncryptionType; 4 | import org.hibernate.HibernateException; 5 | import org.hibernate.engine.spi.SharedSessionContractImplementor; 6 | import org.hibernate.usertype.DynamicParameterizedType; 7 | import org.hibernate.usertype.UserType; 8 | 9 | import javax.persistence.Column; 10 | import java.io.Serializable; 11 | import java.lang.reflect.Field; 12 | import java.sql.PreparedStatement; 13 | import java.sql.ResultSet; 14 | import java.sql.SQLException; 15 | import java.sql.Types; 16 | import java.util.*; 17 | import java.util.stream.Collectors; 18 | 19 | /** 20 | * This class is used to tokenize a field of an entity. it implements the UserType interface 21 | * This class implements the nullSafeSet method which is called by the ORM before persisting the entity and 22 | * before executing the find queries 23 | * In the implementation of the nullSafeSet method, the field value is being replaced by the token id and 24 | * is set to the field. 25 | * The token id is calculated before the entity is persisted and is stored in the vault by using the hash 26 | * method of the TokenApi which retrieves equal token id for deterministic token for the same value. 27 | */ 28 | public class Encrypted implements UserType, DynamicParameterizedType { 29 | 30 | public static final String TYPE = "type"; 31 | public static final String COLLECTION = "collection"; 32 | public static final String PROPERTY = "property"; 33 | 34 | private Encryptor encryptor; 35 | 36 | @Override 37 | public int[] sqlTypes() { 38 | return new int[] { Types.VARCHAR }; 39 | } 40 | 41 | @Override 42 | public Class returnedClass() { 43 | return String.class; 44 | } 45 | 46 | @Override 47 | public boolean equals(Object x, Object y) throws HibernateException { 48 | return Objects.equals(x, y); 49 | } 50 | 51 | @Override 52 | public int hashCode(Object x) throws HibernateException { 53 | return x != null ? x.hashCode() : 0; 54 | } 55 | 56 | @Override 57 | public Object deepCopy(Object value) throws HibernateException { 58 | return value; 59 | } 60 | 61 | @Override 62 | public boolean isMutable() { 63 | return false; 64 | } 65 | 66 | @Override 67 | public Serializable disassemble(Object value) throws HibernateException { 68 | Object deepCopy = deepCopy(value); 69 | if ((deepCopy instanceof Serializable)) { 70 | return (Serializable) deepCopy; 71 | } 72 | return null; 73 | } 74 | 75 | @Override 76 | public Object assemble(Serializable cached, Object owner) throws HibernateException { 77 | return deepCopy(cached); 78 | } 79 | 80 | @Override 81 | public Object replace(Object original, Object target, Object owner) throws HibernateException { 82 | return deepCopy(original); 83 | } 84 | 85 | @Override 86 | public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) 87 | throws HibernateException, SQLException { 88 | 89 | try { 90 | String value = rs.getString(names[0]); 91 | 92 | saveEncryptedValueOnOwner(owner, value); 93 | 94 | if (encryptor.isEncrypted(value)) { 95 | value = encryptor.decrypt(value).toString(); 96 | } 97 | return value; 98 | } catch (Exception e) { 99 | throw new HibernateException(e); 100 | } 101 | } 102 | 103 | @Override 104 | public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) 105 | throws HibernateException, SQLException { 106 | 107 | if (value == null) { 108 | st.setNull(index, Types.VARCHAR); 109 | return; 110 | } 111 | 112 | try { 113 | String propValue = value.toString(); 114 | 115 | if (propValue != null && !encryptor.isEncrypted(propValue)) { 116 | propValue = encryptor.encrypt(propValue); 117 | } 118 | 119 | st.setString(index, propValue); 120 | } catch (Exception e) { 121 | throw new HibernateException(e); 122 | } 123 | } 124 | 125 | @Override 126 | public void setParameterValues(Properties parameters) { 127 | 128 | EncryptionType encryptionType = EncryptionType.DETERMINISTIC; 129 | if (EncryptionType.RANDOMIZED.toString().equalsIgnoreCase(parameters.getProperty(TYPE))) { 130 | encryptionType = EncryptionType.RANDOMIZED; 131 | } 132 | 133 | ParameterType parameterType = (ParameterType) parameters.get(DynamicParameterizedType.PARAMETER_TYPE); 134 | 135 | String collection = parameters.getProperty(COLLECTION) != null ? 136 | parameters.getProperty(COLLECTION) : 137 | parameterType.getTable(); 138 | 139 | String propertyName = parameters.getProperty(PROPERTY); 140 | if (propertyName == null) { 141 | Optional columnName = 142 | Arrays.stream(parameterType.getAnnotationsMethod()) 143 | .filter(a -> a.annotationType().isAssignableFrom(Column.class)) 144 | .map(c -> ((Column) c).name()) 145 | .findFirst(); 146 | 147 | if (columnName.isPresent()) { 148 | propertyName = columnName.get(); 149 | } 150 | } 151 | 152 | encryptor = new Encryptor(encryptionType, collection, propertyName); 153 | } 154 | 155 | private void saveEncryptedValueOnOwner(Object owner, String encryptedValue) throws IllegalAccessException { 156 | Class clazz = owner.getClass(); 157 | Optional propertyField = Arrays.stream(clazz.getDeclaredFields()) 158 | .filter(f -> f.getName().equals(encryptor.getPropertyName())) 159 | .collect(Collectors.toList()) 160 | .stream().findFirst(); 161 | 162 | if (propertyField.isPresent()) { 163 | Field field = propertyField.get(); 164 | field.setAccessible(true); 165 | field.set(owner, encryptedValue); 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /sdk/hibernate-encryption/src/main/java/com/piiano/vault/orm/encryption/Encryptor.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.orm.encryption; 2 | 3 | import com.google.common.collect.ImmutableList; 4 | import com.google.common.collect.ImmutableMap; 5 | import com.piiano.vault.client.CryptoClient; 6 | import com.piiano.vault.client.model.AccessReason; 7 | import com.piiano.vault.client.model.DecryptParams; 8 | import com.piiano.vault.client.model.EncryptParams; 9 | import com.piiano.vault.client.openapi.ApiException; 10 | import com.piiano.vault.client.openapi.model.*; 11 | import lombok.Getter; 12 | 13 | import java.util.Collections; 14 | import java.util.List; 15 | 16 | import static com.piiano.vault.client.VaultClient.getPvaultClient; 17 | 18 | public class Encryptor { 19 | 20 | public static final String PREFIX_ENCRYPTED = "encrypted_"; 21 | 22 | private final CryptoClient cryptoClient; 23 | 24 | private final EncryptionType encryptionType; 25 | 26 | @Getter 27 | private final String collectionName; 28 | 29 | @Getter 30 | private final String propertyName; 31 | 32 | public Encryptor(EncryptionType encryptionType, String collectionName, String propertyName) { 33 | 34 | this.cryptoClient = new CryptoClient(getPvaultClient()); 35 | 36 | this.encryptionType = encryptionType; 37 | this.collectionName = collectionName; 38 | this.propertyName = propertyName; 39 | } 40 | 41 | public boolean isEncrypted(String propValue) { 42 | return propValue != null 43 | && propValue.startsWith(PREFIX_ENCRYPTED); 44 | } 45 | 46 | public String encrypt(String propValue) throws ApiException { 47 | 48 | EncryptionRequest request = new EncryptionRequest() 49 | .type(this.encryptionType) 50 | ._object(new InputObject().fields(ImmutableMap.of(this.propertyName, propValue))); 51 | 52 | List encrypted = this.cryptoClient.encrypt( 53 | EncryptParams.builder() 54 | .collection(this.collectionName) 55 | .encryptionRequest(ImmutableList.of(request)) 56 | .accessReason(AccessReason.AppFunctionality) 57 | .build() 58 | ); 59 | 60 | if (encrypted != null && encrypted.size() == 1) { 61 | return PREFIX_ENCRYPTED + encrypted.get(0).getCiphertext(); 62 | } 63 | return null; 64 | } 65 | 66 | public Object decrypt(String ciphertext) throws ApiException { 67 | 68 | if (ciphertext == null) { 69 | throw new ApiException("ciphertext must not be null"); 70 | } 71 | 72 | if (isEncrypted(ciphertext)) { 73 | ciphertext = ciphertext.substring(PREFIX_ENCRYPTED.length()); 74 | } 75 | 76 | DecryptionRequest request = new DecryptionRequest().encryptedObject( 77 | new EncryptedObjectInput().ciphertext(ciphertext)).props(ImmutableList.of(this.propertyName)); 78 | 79 | List decrypted = this.cryptoClient.decrypt( 80 | DecryptParams.builder() 81 | .collection(this.collectionName) 82 | .decryptionRequests(ImmutableList.of(request)) 83 | .accessReason(AccessReason.AppFunctionality) 84 | .build() 85 | ); 86 | 87 | if (decrypted != null && decrypted.size() == 1) { 88 | return decrypted.get(0).getFields().get(this.propertyName); 89 | } 90 | return null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /sdk/hibernate-encryption/src/main/java/com/piiano/vault/orm/encryption/Transformation.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.orm.encryption; 2 | 3 | import java.lang.annotation.*; 4 | 5 | @Target(ElementType.FIELD) 6 | @Retention(RetentionPolicy.RUNTIME) 7 | public @interface Transformation{ 8 | 9 | // The property name of the field that is annotated as Encrypted and will be transformed (e.g. "ssn") 10 | String property() default ""; 11 | // The name of the transformer to be used (e.g. "mask") 12 | String transformer() default ""; 13 | } -------------------------------------------------------------------------------- /sdk/hibernate-encryption/src/main/java/com/piiano/vault/orm/encryption/TransformationInterceptor.java: -------------------------------------------------------------------------------- 1 | package com.piiano.vault.orm.encryption; 2 | 3 | import com.piiano.vault.client.openapi.ApiException; 4 | import com.piiano.vault.client.openapi.model.EncryptionType; 5 | import lombok.AllArgsConstructor; 6 | import org.hibernate.EmptyInterceptor; 7 | import org.hibernate.annotations.Parameter; 8 | import org.hibernate.type.Type; 9 | import org.jetbrains.annotations.NotNull; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.io.Serializable; 13 | import java.lang.reflect.Field; 14 | import java.util.*; 15 | import java.util.stream.Collectors; 16 | 17 | @Component 18 | public class TransformationInterceptor extends EmptyInterceptor { 19 | 20 | // Intercept the loading of the entity. 21 | // onLoad is called after the Encrypted types are decrypted. 22 | // In Encrypted.nullSafeGet, (see saveEncryptedValueOnOwner) the Encrypted instance set the encrypted value 23 | // on the respective properties of the owner which is passed here in the first argument. 24 | // onLoad reflects on the entity and discovers all the properties that are annotated with @Transformation. 25 | // Let's call those the transformation fields. 26 | // The Transformation annotation specifies the name of the encrypted field and the name of the transformer 27 | // that should be applied to the decrypted value of that field in order to set the value of the transformation field. 28 | // For each transformation field, the interceptor creates an instance of Encryptor and decrypts the value of the 29 | // encrypted field specifying the transformer that should be applied. It then sets the value of the transformation 30 | // field with the result. 31 | public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) { 32 | try { 33 | calculateTransformationFields(entity); 34 | } catch (ApiException | IllegalAccessException e) { 35 | throw new RuntimeException(e); 36 | } 37 | return super.onLoad(entity, id, state, propertyNames, types); 38 | } 39 | 40 | @AllArgsConstructor 41 | static class TransformationField { 42 | Field entityField; // The field defined in the entity that is annotated with Transformation (e.g. "ssnMask") 43 | String dottedName; // The transformation binding that will be passed to Vault to get the value of the field (e.g. "ssn.mask") 44 | } 45 | 46 | static class TransformationMappings { 47 | TransformationMappings(Field encryptedField) { 48 | this.encryptedField = encryptedField; 49 | this.transformations = new ArrayList<>(); 50 | } 51 | 52 | Field encryptedField; 53 | List transformations; 54 | } 55 | 56 | private static void calculateTransformationFields(Object entity) throws ApiException, IllegalAccessException { 57 | Class clazz = entity.getClass(); 58 | 59 | // the table name is the default collection name unless overridden by the Encrypted annotation 60 | calculateTransformationFields( 61 | entity, 62 | getTableName(clazz), 63 | findTransformations(clazz)); 64 | } 65 | 66 | @NotNull 67 | private static Map findTransformations(Class clazz) { 68 | 69 | // get all fields of the entity - including the transient ones that are not persisted. 70 | // (these are assumed to be transformation fields) 71 | Map allFields = Arrays.stream(clazz.getDeclaredFields()) 72 | .collect(Collectors.toMap( 73 | Field::getName, 74 | field -> field)); 75 | 76 | // find all the transformation fields and create a map of the encrypted field name to the transformation fields 77 | // where the transformation field is a transformation of the encrypted field. 78 | Map transformationMap = new HashMap<>(); 79 | 80 | for (Field field : clazz.getDeclaredFields()) { 81 | if (isTransformationAnnotated(field)) { 82 | Transformation transformationAnnotation = getTransformationField(field); 83 | 84 | TransformationMappings mappings = getTransformationMappings( 85 | transformationMap, 86 | allFields, 87 | transformationAnnotation.property()); 88 | 89 | mappings.transformations.add( 90 | getTransformationField( 91 | field, 92 | transformationAnnotation)); 93 | } 94 | } 95 | return transformationMap; 96 | } 97 | 98 | private static void calculateTransformationFields( 99 | Object entity, 100 | String defaultCollectionName, 101 | Map transformationMap) throws IllegalAccessException, ApiException { 102 | 103 | for (TransformationMappings mappings : transformationMap.values()) { 104 | 105 | Field encryptedField = mappings.encryptedField; 106 | 107 | // The collection name is the default collection name unless overridden by the Encrypted annotation 108 | String collectionName = getUpdatedCollectionName(defaultCollectionName, encryptedField); 109 | 110 | // For each transformation field, the interceptor creates an instance of Encryptor and decrypts the value of the 111 | for (TransformationField transformation : mappings.transformations) { 112 | // Extract the encrypted value from the entity that was placed on the encrypted field by the Encrypted type 113 | String encryptedValue = getFieldValue(entity, encryptedField); 114 | if (encryptedValue == null) { 115 | // If the encrypted value is null (was not set), the transformation cannot be applied. 116 | continue; 117 | } 118 | // Decrypt the value using an Encryptor that calls Vault specifying the dotted name of the transformation. 119 | String decryptedValue = getDecryptedValue(collectionName, transformation.dottedName, encryptedValue); 120 | // Set the decrypted result of the transformation on the transformation field 121 | setFieldValue(transformation.entityField, entity, decryptedValue); 122 | } 123 | } 124 | } 125 | 126 | private static String getUpdatedCollectionName(String defaultName, Field field) { 127 | // The collection name is the default collection name unless overridden by the Encrypted annotation 128 | if (isTypeAnnotated(field)) { 129 | for (Parameter parameter : getTypeAnnotation(field).parameters()) { 130 | if (isCollectionParameter(parameter)) { 131 | return parameter.value(); 132 | } 133 | } 134 | } 135 | return defaultName; 136 | } 137 | 138 | // Create an Encryptor that calls Vault specifying the dotted name of the transformation and decrypt returning the transformed value. 139 | private static String getDecryptedValue(String collectionName, String dottedName, String encryptedValue) throws ApiException { 140 | Encryptor encryptor = new Encryptor( 141 | EncryptionType.DETERMINISTIC, 142 | collectionName, 143 | dottedName); 144 | return encryptor.decrypt(encryptedValue).toString(); 145 | } 146 | 147 | @NotNull 148 | private static TransformationField getTransformationField(Field field, Transformation transformation) { 149 | return new TransformationField( 150 | field, 151 | String.format("%s.%s", transformation.property(), transformation.transformer())); 152 | } 153 | 154 | private static TransformationMappings getTransformationMappings( 155 | Map transformationMap, 156 | Map allFields, 157 | String encryptedPropertyName) { 158 | 159 | if (transformationMap.containsKey(encryptedPropertyName)) { 160 | return transformationMap.get(encryptedPropertyName); 161 | } 162 | 163 | // If this is the first transformation of the encryptedPropertyName, create a new mapping. 164 | Field encryptedField = allFields.get(encryptedPropertyName); 165 | 166 | TransformationMappings mappings = new TransformationMappings(encryptedField); 167 | 168 | // Add the mapping to the map of mappings 169 | transformationMap.put(encryptedPropertyName, mappings); 170 | 171 | return mappings; 172 | } 173 | 174 | private static void setFieldValue(Field entityField, Object entity, String decryptedValue) throws IllegalAccessException { 175 | entityField.setAccessible(true); 176 | entityField.set(entity, decryptedValue); 177 | } 178 | 179 | private static String getFieldValue(Object entity, Field field) throws IllegalAccessException { 180 | field.setAccessible(true); 181 | Object value = field.get(entity); 182 | if (value == null) { 183 | return null; 184 | } 185 | return value.toString(); 186 | } 187 | 188 | // TODO: Assumes that the Type annotation is only used for the Encrypted type. This is not necessarily true. 189 | private static boolean isTypeAnnotated(Field field) { 190 | return field.isAnnotationPresent(org.hibernate.annotations.Type.class); 191 | } 192 | 193 | private static org.hibernate.annotations.Type getTypeAnnotation(Field field) { 194 | return field.getAnnotation(org.hibernate.annotations.Type.class); 195 | } 196 | 197 | private static boolean isTransformationAnnotated(Field field) { 198 | return field.isAnnotationPresent(Transformation.class); 199 | } 200 | 201 | private static Transformation getTransformationField(Field field) { 202 | return field.getAnnotation(Transformation.class); 203 | } 204 | 205 | // We support getting the collection name from the Table annotation or the Encrypted annotation. 206 | // Get the table name here. It may be overridden by the Encrypted annotation. 207 | private static String getTableName(Class clazz) { 208 | if (clazz.isAnnotationPresent(javax.persistence.Table.class)) { 209 | return clazz.getAnnotation(javax.persistence.Table.class).name(); 210 | } 211 | return ""; 212 | } 213 | 214 | private static boolean isCollectionParameter(Parameter parameter) { 215 | return parameter.name().equals(Encrypted.COLLECTION); 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /sdk/patches/pom.patch: -------------------------------------------------------------------------------- 1 | diff --git a/sdk/openapi/pom.xml b/sdk/openapi/pom.xml 2 | index 3e60ee8..2d8c901 100644 3 | --- a/sdk/openapi/pom.xml 4 | +++ b/sdk/openapi/pom.xml 5 | @@ -31,8 +31,26 @@ 6 | 7 | 8 | 9 | + 10 | + 11 | + ossrh 12 | + https://s01.oss.sonatype.org/content/repositories/snapshots 13 | + 14 | + 15 | + 16 | 17 | 18 | + 19 | + org.sonatype.plugins 20 | + nexus-staging-maven-plugin 21 | + 1.6.13 22 | + true 23 | + 24 | + ossrh 25 | + https://s01.oss.sonatype.org/ 26 | + true 27 | + 28 | + 29 | 30 | org.apache.maven.plugins 31 | maven-compiler-plugin 32 | --------------------------------------------------------------------------------