{"id":19602016,"url":"https://github.com/borisdz/document-validation-server","last_synced_at":"2026-06-18T09:32:13.868Z","repository":{"id":255841894,"uuid":"853322774","full_name":"borisdz/Document-Validation-Server","owner":"borisdz","description":"A server for validating documents by their certificate","archived":false,"fork":false,"pushed_at":"2024-09-24T14:54:59.000Z","size":1569,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-21T09:06:29.148Z","etag":null,"topics":["certificate","document-validator","documentation-tool","security","validation-tool"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/borisdz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-06T12:33:45.000Z","updated_at":"2024-09-25T12:36:03.000Z","dependencies_parsed_at":"2024-09-07T12:26:40.506Z","dependency_job_id":"a8c5b5fa-f0a3-4d23-819a-9ea8a66ddfd1","html_url":"https://github.com/borisdz/Document-Validation-Server","commit_stats":null,"previous_names":["borisdz/document-validation-server"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/borisdz/Document-Validation-Server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borisdz%2FDocument-Validation-Server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borisdz%2FDocument-Validation-Server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borisdz%2FDocument-Validation-Server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borisdz%2FDocument-Validation-Server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/borisdz","download_url":"https://codeload.github.com/borisdz/Document-Validation-Server/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/borisdz%2FDocument-Validation-Server/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34485163,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-18T02:00:06.871Z","response_time":128,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["certificate","document-validator","documentation-tool","security","validation-tool"],"created_at":"2024-11-11T09:21:45.328Z","updated_at":"2026-06-18T09:32:13.839Z","avatar_url":"https://github.com/borisdz.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Документација -  Сервер за валидација на документи со сертификати и mTLS - Борис Џотов 185022\n\nЛинк до GitHub од проектот со mTLS и креирање на кориснички профили со верификација на мејл: [https://github.com/borisdz/Document-Validation-Server/tree/master](https://github.com/borisdz/Document-Validation-Server/tree/master)\n\nЛинк до GitHub од проектот само со mTLS: [https://github.com/borisdz/Document-Validation-Server/tree/only-mtls](https://github.com/borisdz/Document-Validation-Server/tree/only-mtls) \n\nНа првиот линк е поставен кодот како што ми беше замислена апликацијата целосно, но не функционира само login методот од сервисот за автентикација, па може само да се пристапи со сертификат и да се регистрира нов корисник, не може да се најави и да стигне до `/document`.\n\nОвој проект претставува изработка на сервер за валидација на документи според сертификатот со кој што истиот е потпишан.\n\nНа серверот исто така има конфигурирано и mTLS (mutual Transport Layer Security). mTLS претставува метод на взаемна автентикација. mTLS се грижи двата корисника или корисник-сервер во мрежата да се оние кои се претставуваат дека се, со тоа што двете страни треба да го имаат коректниот приватен клуч. Информациите кои ги содржат TLS сертификатите соодветно пружаат дополнителна верификација.\n\nmTLS најчесто се користи во Zero Trust security framework да се верифицираат корисници, уреди и сервери во една организација. Оваа рамка всушност значи дека ниеден корисник, уред или проток во мрежата не е веродостоен.\n\n## mTLS конфигурација во Spring Boot веб апликацијата\n\n### Генерирање на потребни клучеви, сертификати и trust stores\n\n```\nkeytool -genkeypair -alias server -keyalg RSA -keysize 4096 -validity 365 -dname \"CN=Server_185022,OU=IB,O=FINKI,L=Skopje,S=SK,C=MK\" -keypass password -keystore server.p12 -storeType PKCS12 -storepass password\n\nkeytool -genkeypair -alias client -keyalg RSA -keysize 4096 -validity 365 -dname \"CN=Client_185022,OU=IB,O=FINKI,L=Skopje,S=SK,C=MK\" -keypass password -keystore client.p12 -storeType PKCS12 -storepass password\n\n```\n\nСо двете команди погоре, се генерира фајл `server.p12` и `client.p12` кои содржат пар од јавен и приватен клуч кои се валидни една година. Се користи алгоритамот RSA со големина на клуч - 4096 бити (може да биде од 2048 до 4096 бити). Другите делови од командата се потребни податоци за сертификатот и клучевите.\n\n```\n// export public keys\nkeytool -exportcert -alias client -file client.cer -keystore client.p12 -storepass password\n\nkeytool -exportcert -alias server -file server.cer -keystore server.p12 -storepass password\n\n```\n\nТука се експортираат јавните клучеви во сертификатите `client.cer` и `server.cer` соодветно, па потоа подолу истите се импортираат во trust stores.\n\n```\n//import public keys to trust stores\nkeytool -importcert -keystore client-truststore.p12 -alias server-public -file server.cer -storepass password -noprompt\n\nkeytool -importcert -keystore server-truststore.p12 -alias client-public -file client.cer -storepass password -noprompt\n\n```\n\nПојаснување на некои од поимите:\n\n- CA (Certificate Authority) - Ентитет кој издава дигитални сертификати.\n- Certificate - Дигитална форма на идентификација, како пасош, за апликацијата.\n- Private Key - Таен клуч кој се користи заедно со јавниот сертификат за да се енкриптиратат и декриптираат податоците.\n- Truststore - репозиториум кој ги содржи сертификатиет на кои им се верува (обично СА сертификати).\n- Keystore - репозиториум кој ги содржи сертификаттие заедно со нивните приватни клучеви.\n\n### mTLS конфигурација во application properties и config\n\nСледно треба да се овозможи mTLS енкрипција во апликацијата. Тоа го правиме во `application.properties` во `src/main/java/resources`. Содржината на тој фајл изгледа вака:\n\n![Untitled](readme_media/Untitled.png)\n\nОбјаснување по линии:\n\n- 3: Овде се поставува порта на која ќе може да пристапиме до серверот.\n- 4: Овде се прави enable на SSL, односно се овозможува користење на SSL протоколот.\n- 8-10: Овде се поставуваат параметрите/податоците за серверските сертификати и клучеви. Тип на key store - PKCS12, патека до фајлот `server.p12` (сите сертификати и направени фајлови од погоре ми се ставени во `src/main/java/resources/cert` до каде може да се пристапи со `claspath:` од тековниот фајл), и на крај password за пристапување до trust store-от кој претходно го поставивме со командите погоре.\n- 14-17: Овде се прави исто како за серверот, овој пат за клиент. На 14-та линија се поставува секогаш да се бара автентикација од страна на клиентот, односно да мора да прикаже сертификат при пристапување до страната. Потоа се патека до серверскиот trust store, соодветната лозинка за пристапување до истиот.\n- 19 и 20та линија се поставува протокол на комуникација - `TLS` и верзија на протоколот - `TLSv1.2`.\nСпоред зададената конфигурација, веб апликацијата ќе не носи секогаш на страната за пријавување/регистрирање. За да се олесни демонстрацијата и да избегнам правење база на корисници ова го заобиколив со `SecurityFilterChain`:\n\n![Untitled](readme_media/Untitled1.png)\n\nОва само ги оневозможува логин страната и по одбирање на сертификат не носи директно на `https://localhost:8443/`.\nПристапувањето до странта изгледа вака:\n\n![Untitled](readme_media/Untitled2.png)\n\nДобиваме прозорче за да избереме сертификат, од каде го избираме Клиент сертификатот кој го креиравме претходно и го инсталиравме на нашиот компјутер (`windows+R-\u003emmc-\u003ecertificates`). По избирање на валидниот сертификат нѝ е овозможен пристап до страната и не води на почетната односно `/`.\n\n![Untitled](readme_media/Untitled3.png)\n\nКатанчето има `!` затоа што серверскиот сертификат ни е self-signed.\n\nСледно е конфигурацијата за читање на документи и валидирање на истите.\n\n## Кориснички профили со верификација на корисничката електронска пошта\n\nЗа да го направам ова прво, ги додадов потребните dependencies во `pom.xml` :\n\n![image.png](readme_media/image.png)\n\nЗависности за базата на податоци - користев `PostgreSQL`, `Spring JPA` и `Spring Boot Starter Mail` за да може да се испраќа елекронска пошта до корисниците.\n\n### Поставување на `application.properties`\n\nСледно се конфигурираат поставките на апликацијата - `application.properties` за да може да се користат сервисите за мејл и бази на податоци:\n\n![image.png](readme_media/image1.png)\n\n- Овде прво се подесуваат поставките за сервисот за електронска пошта, `host` кој го користев е `gmail` , порта на која слуша `smtp` протоколот, корисничката сметка на `gmail` од која ќе се праќаат електронската пошта, лозинка која ја генерирав на страната на `gmail` која ја користам само овде. Исто така се подесува да се користи автентикација и `tls` протокол за поштата.\n- За базата на податоци имам стандардни поставувања, линк до локалната база, корисничко име и лозинка, последниот ред е за да се претвора од `jpa` код во `sql` .\n\n### Поставување на `WebSecurityConfig.java`\n\nИсто така треба да се промени и конфигурацискиот фајл за web security.\n\n![image.png](readme_media/image2.png)\n\nСега овој фајл изгледа многу поразлично од претходно. \n\n- Најпрво се додава custom филтер за да секогаш кога ќе се пристапи за прв пат до страната најпрво да се побара сертификат од корисникот, па потоа пренасочува кон `/login` .\n- Следно на `login` делот се дозволува пристап до страната и доколку е успешно најавувањето, ставив custom `successHandler` да пренасочува на `/document` како обид да го поправам error-от кој ми се појавува при најавување.\n- Во `logout` делот се подесува URL-то на страната за одјавување, се исчистува постоечката автентикација, се инвалидира http сесијата и се бришат сите колачиња. На крај се редиректира на `/login`.\n\n### Хеширање и чување на корисничката лозинка безбедно во база на податоци\n\nЗа секој корисник покрај корисничката електронска пошта, корисничкото име и корисничката лозинка се чува дополнително поле - `saltValue` од тип `String` .\n\nОваа вредност ја креирам во посебна класа - `PassEncryption` за секој корисник и ја чувам во базата заедно со податоците за корисниците, затоа што со помош на оваа вредност лозинката на корисникот се хешира на побезбеден начин.\n\n![image.png](readme_media/image3.png)\n\n### Разгледување на методот за регистрирање корисник\n\nЗаради тоа што овој метод е поспецифичен со верификација со помош на електронска пошта и хеширање на лозинка ќе го разгледаме него подетално.\n\n![image.png](readme_media/image4.png)\n\n- Се генерира `saltValue` за корисникот.\n- Се зачувува во објект од тип `User` електронската пошта, корисничкото име, празна лозинка и улога во системот.\n- Се поставува лозинката да биде хеширана вредност од лозинката која корисникот ја внел заедно во комбинација со генерираната `saltValue` специфична за него.\n- Така се зачувува во базата.\n- Следно се генерира токен за потврдување за корисникот со помош на конструктор за објектот за токен. Токенот се генерира со следниот код:\n\n![image.png](readme_media/image5.png)\n\n- Истиот се зачувува во репозиториумот за токени.\n- Се креира објект од типот `SimpleMailMessage` кој всушност претставува едно електронско писмо.\n    - Се поставува примачот да биде елекронската пошта на корисникот.\n    - Се поставува предмет на писмото да биде „Complete Registration!“.\n    - Се поставува телото на писмото да биде текст и линк до `register/confirm-account?token=` на кое е залепен генерираниот токен за корисникот.\n    - Писмото се испраќа и објектот од корисникот повторно се зачувува во репозиториумот за корисници.\n\nОна што корисникот го добива во своето сандаче изгледа вака:\n\n![image.png](readme_media/image6.png)\n\nВо контролерот за регистрирање - `RegisterController` е методот до кој води линкот кој го испративме на корисникот:\n\n![image.png](readme_media/image7.png)\n\nТука се повикува функција од `userService` - `confirmEmail` .\n\n![image.png](readme_media/image8.png)\n\nОвде како аргумент функцијата го прима токенот. Го наоѓа истиот од репозиториумот на токени. Го наоѓа корисникот со помош на корисничката е-пошта која е во токенот и тој корисник го сетира на `user.setEnabled(true)` . Со ова се верифицира е-поштата која корисникот ја дал на системот при регистрација.\n\n## Валидирање на документи\n\n![Untitled](readme_media/Untitled4.png)\n\nИскоментиран ми е кодот за оддвојување на корисничкиот сертификат од http request-от и кодот за валидирање на word (.docx) документи затоа што тие два дела не ми профункционираа.\nТука најпрво имаме проверка на тип на фајл, па потоа соодветно истиот се препраќа на соодветната функција од сервисот за валидирање на .pdf или .docx фајл. Доколку е валиден сертификатот на документот се редиректира до страна `valid.html` или до страна `invalid.html` доколку не е валиден.\nАјде да ја погледнеме функцијата од сервисот за валидирање на `.pdf` документи.\n\n![Untitled](readme_media/Untitled5.png)\n\nЗа работење со .pdf документи ги користам библиотеките на `itextpdf`.\nНајпрво го предаваме фајлот на 'pdf читач' како stream. Се креира објект `PdfDocument` од истиот stream за да може да манипулираме со истиот. Исто така се креира објект од типот `SignatureUtil` кој е алатка за пристапување и манипулирање со потписот на pdf документот.\nМоже да има повеќе потписи во еден документ па затоа правиме листа од потписи.\nЗа секој потпис во таа листа се 'извлекува' сертификатот од потписот и се зачувува во PKCS7 формат. Потоа истиот се валидира.\n\nТука сертификатот може да се валидира според повеќе работи, дали потписот е прво валиден, дали сертификатот е истечен, дали потписот е revoked - `isRevocationValid` , може да се провери интегритет и автентичност, како и да се провери `verifyTimestampImprint` .\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fborisdz%2Fdocument-validation-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fborisdz%2Fdocument-validation-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fborisdz%2Fdocument-validation-server/lists"}