diff --git a/CONFIGURATION.md b/CONFIGURATION.md new file mode 100644 index 0000000..a08639e --- /dev/null +++ b/CONFIGURATION.md @@ -0,0 +1,108 @@ +# Configuration GBCM Server + +## Vue d'ensemble + +Le serveur GBCM utilise Quarkus avec des profils de configuration pour différents environnements. + +## Profils disponibles + +### Profil par défaut (Production) +- Base de données PostgreSQL +- JWT avec clés RSA +- Logs au niveau WARN +- Sécurité renforcée + +### Profil `dev` (Développement) +- Base de données H2 en mémoire +- Logs au niveau DEBUG +- Sécurité allégée (BCrypt cost=4) +- Rechargement automatique + +### Profil `test` (Tests) +- Base de données H2 en mémoire +- Configuration optimisée pour les tests +- Sécurité minimale pour rapidité + +### Profil `local` (Développement local) +- Configuration personnalisable +- Utilise `application-local.properties` + +## Variables d'environnement importantes + +### Base de données (Production) +```bash +DATABASE_URL=jdbc:postgresql://localhost:5432/gbcm_prod +DB_USERNAME=gbcm_prod_user +DB_PASSWORD=secure_password +``` + +### JWT (Production) +```bash +JWT_SECRET=your-super-secure-jwt-secret-key-256-bits-minimum +``` + +### Email (Production) +```bash +SMTP_USERNAME=your-smtp-username +SMTP_PASSWORD=your-smtp-password +``` + +## Configuration de sécurité + +### Paramètres JWT +- `gbcm.security.jwt.access-token.duration`: Durée de vie des tokens d'accès (défaut: 1h) +- `gbcm.security.jwt.refresh-token.duration`: Durée de vie des refresh tokens (défaut: 7j) +- `gbcm.security.jwt.reset-token.duration`: Durée de vie des tokens de reset (défaut: 2h) + +### Paramètres de mot de passe +- `gbcm.security.password.bcrypt-cost`: Coût BCrypt (défaut: 12) +- `gbcm.security.password.min-length`: Longueur minimale (défaut: 8) +- `gbcm.security.password.max-age`: Âge maximum (défaut: 90j) + +### Paramètres de compte +- `gbcm.security.account.max-failed-attempts`: Tentatives max (défaut: 5) +- `gbcm.security.account.lockout-duration`: Durée de verrouillage (défaut: 30min) + +## Démarrage rapide + +### Développement avec H2 +```bash +mvn quarkus:dev +``` + +### Développement avec configuration locale +```bash +mvn quarkus:dev -Dquarkus.profile=local +``` + +### Tests +```bash +mvn test +``` + +### Production +```bash +java -jar target/quarkus-app/quarkus-run.jar -Dquarkus.profile=prod +``` + +## URLs importantes + +- Application: http://localhost:8081 +- Swagger UI: http://localhost:8081/swagger +- Health Check: http://localhost:8081/health +- Metrics: http://localhost:8081/q/metrics + +## Sécurité + +⚠️ **Important**: +- Changez toujours `JWT_SECRET` en production +- Utilisez des mots de passe forts pour la base de données +- Configurez HTTPS en production +- Limitez les origines CORS en production + +## Logs + +Les logs sont configurés par niveau : +- `com.gbcm`: DEBUG en développement, INFO en production +- `org.hibernate.SQL`: DEBUG en développement seulement +- Root level: DEBUG en dev, WARN en production diff --git a/pom.xml b/pom.xml index 0f77432..1bdcf44 100644 --- a/pom.xml +++ b/pom.xml @@ -65,6 +65,10 @@ io.quarkus quarkus-jdbc-postgresql + + io.quarkus + quarkus-jdbc-h2 + io.quarkus quarkus-flyway diff --git a/src/main/java/com/gbcm/server/impl/entity/User.java b/src/main/java/com/gbcm/server/impl/entity/User.java index a93c8b9..46b6a1b 100644 --- a/src/main/java/com/gbcm/server/impl/entity/User.java +++ b/src/main/java/com/gbcm/server/impl/entity/User.java @@ -111,9 +111,17 @@ public class User extends BaseEntity { @Enumerated(EnumType.STRING) @Column(name = "role", nullable = false, length = 20) @NotNull(message = "Le rôle est obligatoire") - @Roles private UserRole role; + /** + * Rôle de l'utilisateur sous forme de String pour Quarkus Security JPA. + * Cette propriété est utilisée par le système de sécurité pour l'authentification. + */ + @Roles + public String getRoleString() { + return role != null ? role.name() : null; + } + /** * Statut d'activation du compte utilisateur. * true = compte actif, false = compte désactivé. diff --git a/src/main/java/com/gbcm/server/impl/resource/AuthResource.java b/src/main/java/com/gbcm/server/impl/resource/AuthResource.java index 7167973..f3a7d1b 100644 --- a/src/main/java/com/gbcm/server/impl/resource/AuthResource.java +++ b/src/main/java/com/gbcm/server/impl/resource/AuthResource.java @@ -165,6 +165,7 @@ public class AuthResource { */ @POST @Path("/refresh") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Operation( summary = "Rafraîchissement du token", description = "Génère un nouveau token d'authentification à partir d'un refresh token" @@ -257,6 +258,7 @@ public class AuthResource { */ @POST @Path("/forgot-password") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Operation( summary = "Mot de passe oublié", description = "Envoie un email de réinitialisation de mot de passe à l'utilisateur" @@ -300,6 +302,7 @@ public class AuthResource { */ @POST @Path("/reset-password") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Operation( summary = "Réinitialisation du mot de passe", description = "Réinitialise le mot de passe avec un token de réinitialisation" @@ -346,6 +349,7 @@ public class AuthResource { */ @PUT @Path("/change-password") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Operation( summary = "Changement de mot de passe", description = "Change le mot de passe d'un utilisateur authentifié" diff --git a/src/main/java/com/gbcm/server/impl/resource/UserResource.java b/src/main/java/com/gbcm/server/impl/resource/UserResource.java index 178f884..9bf4722 100644 --- a/src/main/java/com/gbcm/server/impl/resource/UserResource.java +++ b/src/main/java/com/gbcm/server/impl/resource/UserResource.java @@ -368,6 +368,7 @@ public class UserResource { */ @PUT @Path("/{id}/status") + @Consumes(MediaType.APPLICATION_FORM_URLENCODED) @RolesAllowed({"ADMIN", "MANAGER"}) @Operation( summary = "Changer le statut d'un utilisateur", diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties new file mode 100644 index 0000000..e8e594a --- /dev/null +++ b/src/main/resources/application-local.properties @@ -0,0 +1,38 @@ +# Configuration locale pour développement GBCM +# Ce fichier peut être utilisé pour surcharger les configurations par défaut +# Copiez ce fichier vers application-local.properties et modifiez selon vos besoins + +# Base de données locale PostgreSQL (optionnel) +# Décommentez et modifiez si vous voulez utiliser PostgreSQL en local +#quarkus.datasource.db-kind=postgresql +#quarkus.datasource.username=gbcm_local +#quarkus.datasource.password=gbcm_local_password +#quarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/gbcm_local +#quarkus.hibernate-orm.database.generation=validate +#quarkus.flyway.migrate-at-start=true + +# Configuration JWT locale +gbcm.security.jwt.secret=local-development-secret-key-change-me +gbcm.security.jwt.access-token.duration=PT2H +gbcm.security.jwt.refresh-token.duration=P1D + +# Configuration email locale (pour tests) +quarkus.mailer.mock=true +quarkus.mailer.from=dev@localhost + +# Configuration de sécurité allégée pour développement +gbcm.security.password.bcrypt-cost=4 +gbcm.security.account.max-failed-attempts=10 +gbcm.security.account.lockout-duration=PT2M + +# Logs détaillés pour développement +quarkus.log.category."com.gbcm.server.impl.service.security".level=TRACE +quarkus.log.category."com.gbcm.server.impl.service.notification".level=DEBUG + +# CORS étendu pour développement +quarkus.http.cors.origins=http://localhost:3000,http://localhost:8080,http://localhost:4200 + +# Configuration OpenAPI étendue +mp.openapi.extensions.smallrye.info.description=API GBCM - Environnement de développement local +quarkus.swagger-ui.enable=true +quarkus.swagger-ui.always-include=true diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 564aa7a..24a9529 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -37,6 +37,21 @@ smallrye.jwt.new-token.issuer=https://gbcm.com smallrye.jwt.new-token.audience=gbcm-users smallrye.jwt.new-token.lifespan=3600 +# GBCM Security Configuration +gbcm.security.jwt.access-token.duration=PT1H +gbcm.security.jwt.refresh-token.duration=P7D +gbcm.security.jwt.reset-token.duration=PT2H +gbcm.security.jwt.secret=${JWT_SECRET:gbcm-super-secret-key-change-in-production} +gbcm.security.password.bcrypt-cost=12 +gbcm.security.password.min-length=8 +gbcm.security.password.require-uppercase=true +gbcm.security.password.require-lowercase=true +gbcm.security.password.require-digit=true +gbcm.security.password.require-special=true +gbcm.security.account.max-failed-attempts=5 +gbcm.security.account.lockout-duration=PT30M +gbcm.security.password.max-age=P90D + # OpenAPI Configuration quarkus.smallrye-openapi.path=/swagger-ui quarkus.swagger-ui.always-include=true @@ -81,12 +96,20 @@ quarkus.log.category."org.hibernate.SQL".level=DEBUG %dev.quarkus.datasource.db-kind=h2 %dev.quarkus.hibernate-orm.database.generation=drop-and-create %dev.quarkus.flyway.migrate-at-start=false +%dev.gbcm.security.jwt.secret=dev-secret-key-not-for-production +%dev.gbcm.security.password.bcrypt-cost=4 +%dev.gbcm.security.account.max-failed-attempts=10 +%dev.gbcm.security.account.lockout-duration=PT5M # Test Profile %test.quarkus.datasource.jdbc.url=jdbc:h2:mem:gbcm_server_test;DB_CLOSE_DELAY=-1 %test.quarkus.datasource.db-kind=h2 %test.quarkus.hibernate-orm.database.generation=drop-and-create %test.quarkus.flyway.migrate-at-start=false +%test.gbcm.security.jwt.secret=test-secret-key-for-testing-only +%test.gbcm.security.password.bcrypt-cost=4 +%test.gbcm.security.account.max-failed-attempts=3 +%test.gbcm.security.account.lockout-duration=PT1M # Production Profile %prod.quarkus.log.level=WARN diff --git a/src/main/resources/import.sql b/src/main/resources/import.sql index ca92a0a..b57e3db 100644 --- a/src/main/resources/import.sql +++ b/src/main/resources/import.sql @@ -3,20 +3,20 @@ -- Insertion des utilisateurs de test -- Mot de passe pour tous: "password123" (hash BCrypt) -INSERT INTO users (first_name, last_name, email, password_hash, role, active, created_by) VALUES -('Admin', 'System', 'admin@gbcm.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'ADMIN', true, 'system'), -('John', 'Manager', 'manager@gbcm.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'MANAGER', true, 'system'), -('Sarah', 'Coach', 'sarah.coach@gbcm.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'COACH', true, 'system'), -('Michael', 'Expert', 'michael.expert@gbcm.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'COACH', true, 'system'), -('Emily', 'Johnson', 'emily.johnson@techcorp.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'CLIENT', true, 'system'), -('David', 'Smith', 'david.smith@innovate.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'CLIENT', true, 'system'), -('Lisa', 'Brown', 'lisa.brown@startup.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'PROSPECT', true, 'system'), -('Robert', 'Wilson', 'robert.wilson@enterprise.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'PROSPECT', true, 'system'); +INSERT INTO users (first_name, last_name, email, password_hash, role, active, deleted, created_by) VALUES +('Admin', 'System', 'admin@gbcm.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'ADMIN', true, false, 'system'), +('John', 'Manager', 'manager@gbcm.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'MANAGER', true, false, 'system'), +('Sarah', 'Coach', 'sarah.coach@gbcm.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'COACH', true, false, 'system'), +('Michael', 'Expert', 'michael.expert@gbcm.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'COACH', true, false, 'system'), +('Emily', 'Johnson', 'emily.johnson@techcorp.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'CLIENT', true, false, 'system'), +('David', 'Smith', 'david.smith@innovate.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'CLIENT', true, false, 'system'), +('Lisa', 'Brown', 'lisa.brown@startup.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'PROSPECT', true, false, 'system'), +('Robert', 'Wilson', 'robert.wilson@enterprise.com', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iAt6Z5EHsM8lE9P8jW9TjnOvQF9G', 'PROSPECT', true, false, 'system'); -- Insertion des coaches -INSERT INTO coaches (user_id, specialization, bio, years_of_experience, certifications, languages, hourly_rate, status, available_for_booking, working_hours_start, working_hours_end, working_days, timezone, start_date, average_rating, total_ratings, total_sessions, total_revenue, created_by) VALUES -(3, 'Strategic Planning', 'Expert en planification stratégique avec plus de 10 ans d''expérience dans le conseil aux PME. Spécialisée dans la transformation digitale et l''optimisation des processus.', 10, 'Certified Management Consultant (CMC), PMP, Lean Six Sigma Black Belt', 'English, French, Spanish', 125.00, 'ACTIVE', true, '09:00:00', '17:00:00', 'MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY', 'America/New_York', '2020-01-15', 4.8, 45, 120, 15000.00, 'system'), -(4, 'Business Development', 'Coach expérimenté en développement commercial et leadership. Aide les entrepreneurs à développer leurs compétences managériales et à faire croître leur entreprise.', 8, 'Certified Business Coach (CBC), MBA, Dale Carnegie Leadership Training', 'English, French', 100.00, 'ACTIVE', true, '08:00:00', '18:00:00', 'MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY', 'America/New_York', '2021-03-01', 4.9, 38, 95, 9500.00, 'system'); +INSERT INTO coaches (user_id, specialization, bio, years_of_experience, certifications, languages, hourly_rate, status, available_for_booking, working_hours_start, working_hours_end, working_days, timezone, start_date, average_rating, total_ratings, total_sessions, total_revenue, deleted, created_by) VALUES +(3, 'Strategic Planning', 'Expert en planification stratégique avec plus de 10 ans d''expérience dans le conseil aux PME. Spécialisée dans la transformation digitale et l''optimisation des processus.', 10, 'Certified Management Consultant (CMC), PMP, Lean Six Sigma Black Belt', 'English, French, Spanish', 125.00, 'ACTIVE', true, '09:00:00', '17:00:00', 'MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY', 'America/New_York', '2020-01-15', 4.8, 45, 120, 15000.00, false, 'system'), +(4, 'Business Development', 'Coach expérimenté en développement commercial et leadership. Aide les entrepreneurs à développer leurs compétences managériales et à faire croître leur entreprise.', 8, 'Certified Business Coach (CBC), MBA, Dale Carnegie Leadership Training', 'English, French', 100.00, 'ACTIVE', true, '08:00:00', '18:00:00', 'MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY', 'America/New_York', '2021-03-01', 4.9, 38, 95, 9500.00, false, 'system'); -- Insertion des types de services pour les coaches INSERT INTO coach_service_types (coach_id, service_type) VALUES @@ -28,11 +28,11 @@ INSERT INTO coach_service_types (coach_id, service_type) VALUES (2, 'special_project'); -- Insertion des clients -INSERT INTO clients (user_id, company_name, industry, company_size, annual_revenue, address_line1, city, state, postal_code, country, website, status, converted_at, primary_service_type, total_contract_value, relationship_start_date, acquisition_source, created_by) VALUES -(5, 'TechCorp Solutions', 'Technology', 50, 2500000.00, '123 Tech Street', 'Atlanta', 'GA', '30309', 'USA', 'https://techcorp.com', 'ACTIVE', '2023-06-15 10:30:00', 'strategic_workshop', 4000.00, '2023-06-15', 'Website', 'system'), -(6, 'Innovate Inc', 'Consulting', 25, 1200000.00, '456 Innovation Ave', 'Atlanta', 'GA', '30308', 'USA', 'https://innovate.com', 'ACTIVE', '2023-08-20 14:15:00', 'one_on_one_coaching', 2500.00, '2023-08-20', 'Referral', 'system'); +INSERT INTO clients (user_id, company_name, industry, company_size, annual_revenue, address_line1, city, state, postal_code, country, website, status, converted_at, primary_service_type, total_contract_value, relationship_start_date, acquisition_source, deleted, created_by) VALUES +(5, 'TechCorp Solutions', 'Technology', 50, 2500000.00, '123 Tech Street', 'Atlanta', 'GA', '30309', 'USA', 'https://techcorp.com', 'ACTIVE', '2023-06-15 10:30:00', 'strategic_workshop', 4000.00, '2023-06-15', 'Website', false, 'system'), +(6, 'Innovate Inc', 'Consulting', 25, 1200000.00, '456 Innovation Ave', 'Atlanta', 'GA', '30308', 'USA', 'https://innovate.com', 'ACTIVE', '2023-08-20 14:15:00', 'one_on_one_coaching', 2500.00, '2023-08-20', 'Referral', false, 'system'); -- Insertion des prospects -INSERT INTO clients (user_id, company_name, industry, company_size, annual_revenue, address_line1, city, state, postal_code, country, website, status, acquisition_source, created_by) VALUES -(7, 'StartupCo', 'E-commerce', 10, 500000.00, '789 Startup Blvd', 'Atlanta', 'GA', '30307', 'USA', 'https://startupco.com', 'PROSPECT', 'LinkedIn', 'system'), -(8, 'Enterprise Corp', 'Manufacturing', 200, 15000000.00, '321 Enterprise Way', 'Atlanta', 'GA', '30306', 'USA', 'https://enterprise.com', 'PROSPECT', 'Trade Show', 'system'); +INSERT INTO clients (user_id, company_name, industry, company_size, annual_revenue, address_line1, city, state, postal_code, country, website, status, acquisition_source, deleted, created_by) VALUES +(7, 'StartupCo', 'E-commerce', 10, 500000.00, '789 Startup Blvd', 'Atlanta', 'GA', '30307', 'USA', 'https://startupco.com', 'PROSPECT', 'LinkedIn', false, 'system'), +(8, 'Enterprise Corp', 'Manufacturing', 200, 15000000.00, '321 Enterprise Way', 'Atlanta', 'GA', '30306', 'USA', 'https://enterprise.com', 'PROSPECT', 'Trade Show', false, 'system');