diff --git a/docker-compose.yml b/docker-compose.yml index 33d12b7..051b4d3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -21,22 +21,30 @@ services: image: quay.io/keycloak/keycloak:26.0 container_name: ecosplay-auth-keycloak restart: unless-stopped - command: start-dev + command: ["start", "--import-realm"] environment: KC_DB: postgres KC_DB_URL: jdbc:postgresql://postgres:5432/keycloak KC_DB_USERNAME: keycloak KC_DB_PASSWORD: keycloak - KC_HOSTNAME: localhost + KC_HOSTNAME: https://auth.e-cosplay.fr KC_HTTP_ENABLED: "true" + KC_PROXY_HEADERS: xforwarded KC_HEALTH_ENABLED: "true" KC_METRICS_ENABLED: "true" - KEYCLOAK_ADMIN: admin - KEYCLOAK_ADMIN_PASSWORD: admin + KC_BOOTSTRAP_ADMIN_USERNAME: admin + KC_BOOTSTRAP_ADMIN_PASSWORD: admin ports: - - "9450:8080" + - "127.0.0.1:9450:8080" volumes: - ./themes/ecosplay:/opt/keycloak/themes/ecosplay:ro + - ./realms:/opt/keycloak/data/import:ro + healthcheck: + test: ["CMD-SHELL", "exec 3<>/dev/tcp/localhost/9000 && printf 'GET /health/ready HTTP/1.0\\r\\nHost: localhost\\r\\n\\r\\n' >&3 && grep -q UP <&3"] + interval: 10s + timeout: 5s + retries: 30 + start_period: 120s depends_on: postgres: condition: service_healthy @@ -48,7 +56,7 @@ services: container_name: ecosplay-auth-init depends_on: keycloak: - condition: service_started + condition: service_healthy environment: KC_SERVER: http://keycloak:8080 KC_ADMIN: admin diff --git a/realms/ecosplay-realm.json b/realms/ecosplay-realm.json new file mode 100644 index 0000000..08b3cdb --- /dev/null +++ b/realms/ecosplay-realm.json @@ -0,0 +1,85 @@ +{ + "realm": "ecosplay", + "displayName": "E-Cosplay", + "displayNameHtml": "E-Cosplay", + "enabled": true, + + "loginTheme": "ecosplay", + "accountTheme": "ecosplay", + "emailTheme": "ecosplay", + "adminTheme": "keycloak.v2", + + "internationalizationEnabled": true, + "supportedLocales": ["fr"], + "defaultLocale": "fr", + + "registrationAllowed": true, + "registrationEmailAsUsername": true, + "rememberMe": true, + "verifyEmail": true, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": true, + "editUsernameAllowed": false, + + "bruteForceProtected": true, + "permanentLockout": false, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 5, + + "passwordPolicy": "length(10) and specialChars(1) and digits(1) and upperCase(1) and lowerCase(1) and notUsername(undefined) and notEmail(undefined)", + + "accessTokenLifespan": 300, + "accessTokenLifespanForImplicitFlow": 900, + "ssoSessionIdleTimeout": 1800, + "ssoSessionMaxLifespan": 36000, + "offlineSessionIdleTimeout": 2592000, + "actionTokenGeneratedByUserLifespan": 900, + + "smtpServer": { + "host": "email-smtp.eu-west-3.amazonaws.com", + "port": "587", + "from": "auth@e-cosplay.fr", + "fromDisplayName": "E-Cosplay", + "replyTo": "noreply@e-cosplay.fr", + "envelopeFrom": "auth@e-cosplay.fr", + "auth": "true", + "starttls": "true", + "ssl": "false", + "user": "AKIAWTT2T22CWBRBBDYN", + "password": "BBdgb6KxRQ8mNcpWFJsZCJxbSGNdgLhKFiITMErfBlQP" + }, + + "clients": [ + { + "clientId": "ecosplay-web", + "name": "E-Cosplay Web", + "description": "Application web principale e-cosplay.fr", + "enabled": true, + "publicClient": false, + "secret": "change-me-in-admin-console", + "redirectUris": [ + "https://www.e-cosplay.fr/*", + "https://e-cosplay.fr/*" + ], + "webOrigins": [ + "https://www.e-cosplay.fr", + "https://e-cosplay.fr" + ], + "protocol": "openid-connect", + "standardFlowEnabled": true, + "implicitFlowEnabled": false, + "directAccessGrantsEnabled": false, + "serviceAccountsEnabled": false, + "frontchannelLogout": true, + "attributes": { + "post.logout.redirect.uris": "https://www.e-cosplay.fr/*##https://e-cosplay.fr/*", + "pkce.code.challenge.method": "S256" + } + } + ] +} diff --git a/themes/ecosplay/account/resources/css/account.css b/themes/ecosplay/account/resources/css/account.css new file mode 100644 index 0000000..ebd7c7e --- /dev/null +++ b/themes/ecosplay/account/resources/css/account.css @@ -0,0 +1,228 @@ +/* ============================================================ + E-Cosplay neo-brutalist overlay for the v2 (PatternFly) account console + ============================================================ */ + +:root { + --pf-v5-global--primary-color--100: #4f46e5; + --pf-v5-global--primary-color--200: #4338ca; + --pf-v5-global--primary-color--light-100: #6366f1; + --pf-v5-global--link--Color: #4f46e5; + --pf-v5-global--link--Color--hover: #111827; + --pf-v5-global--BackgroundColor--100: #fbfbfb; + --pf-v5-global--BackgroundColor--200: #ffffff; + --pf-v5-global--BorderColor--100: #111827; + --pf-v5-global--FontFamily--text: ui-sans-serif, system-ui, -apple-system, + "Segoe UI", Roboto, sans-serif; + --pf-v5-global--FontFamily--heading: ui-sans-serif, system-ui, -apple-system, + "Segoe UI", Roboto, sans-serif; + --pf-v5-global--FontFamily--monospace: ui-monospace, "SFMono-Regular", + Menlo, monospace; + --pf-v5-global--FontWeight--bold: 900; + --pf-v5-global--BorderRadius--sm: 0; + --pf-v5-global--BorderRadius--lg: 0; +} + +html, +body, +.pf-v5-c-page, +.pf-v5-c-page__main { + background-color: #fbfbfb !important; + font-style: italic; +} + +/* Header band */ +.pf-v5-c-masthead { + background-color: #111827 !important; + border-bottom: 4px solid #4f46e5 !important; +} + +.pf-v5-c-masthead__brand, +.pf-v5-c-masthead__main { + color: #ffffff !important; + font-weight: 900 !important; + text-transform: uppercase !important; + letter-spacing: 0.15em !important; + font-style: italic !important; +} + +/* Cards */ +.pf-v5-c-card { + background-color: #ffffff !important; + border: 4px solid #111827 !important; + border-radius: 0 !important; + box-shadow: 8px 8px 0 rgba(0, 0, 0, 1) !important; +} + +.pf-v5-c-card__title, +.pf-v5-c-card__title-text { + text-transform: uppercase !important; + font-style: italic !important; + font-weight: 900 !important; + letter-spacing: -0.02em !important; +} + +/* Headings */ +h1, +h2, +h3, +.pf-v5-c-title, +.pf-v5-c-content h1, +.pf-v5-c-content h2, +.pf-v5-c-content h3 { + text-transform: uppercase !important; + font-style: italic !important; + font-weight: 900 !important; + letter-spacing: -0.025em !important; + color: #111827 !important; +} + +/* Form labels */ +.pf-v5-c-form__label, +.pf-v5-c-form__label-text { + text-transform: uppercase !important; + font-weight: 900 !important; + letter-spacing: 0.1em !important; + font-size: 11px !important; + color: #111827 !important; + font-style: normal !important; +} + +/* Inputs */ +.pf-v5-c-form-control, +.pf-v5-c-form-control input, +input.pf-v5-c-form-control, +.pf-v5-c-text-input-group__text-input { + border: 4px solid #111827 !important; + border-radius: 0 !important; + background-color: #ffffff !important; + color: #111827 !important; + font-weight: 700 !important; + font-style: normal !important; + padding: 12px 14px !important; + height: auto !important; +} + +.pf-v5-c-form-control:focus, +.pf-v5-c-form-control:focus-within { + background-color: #fef9c3 !important; + box-shadow: 6px 6px 0 #4f46e5 !important; + outline: none !important; +} + +/* Buttons */ +.pf-v5-c-button { + border-radius: 0 !important; + border: 4px solid #111827 !important; + font-weight: 900 !important; + text-transform: uppercase !important; + letter-spacing: 0.12em !important; + font-style: italic !important; + padding: 14px 24px !important; + transition: all 0.15s ease !important; +} + +.pf-v5-c-button.pf-m-primary { + background-color: #4f46e5 !important; + color: #ffffff !important; + box-shadow: 6px 6px 0 rgba(0, 0, 0, 1) !important; +} + +.pf-v5-c-button.pf-m-primary:hover { + background-color: #4338ca !important; + box-shadow: none !important; + transform: translate(4px, 4px) !important; +} + +.pf-v5-c-button.pf-m-secondary { + background-color: #ffffff !important; + color: #111827 !important; + box-shadow: 6px 6px 0 rgba(0, 0, 0, 1) !important; +} + +.pf-v5-c-button.pf-m-secondary:hover { + background-color: #facc15 !important; + box-shadow: none !important; + transform: translate(4px, 4px) !important; +} + +.pf-v5-c-button.pf-m-danger { + background-color: #dc2626 !important; + color: #ffffff !important; + box-shadow: 6px 6px 0 rgba(0, 0, 0, 1) !important; +} + +.pf-v5-c-button.pf-m-link { + color: #4f46e5 !important; + border: 0 !important; + box-shadow: none !important; + text-decoration: underline !important; + text-underline-offset: 4px !important; + text-decoration-thickness: 3px !important; + padding: 4px 8px !important; +} + +.pf-v5-c-button.pf-m-link:hover { + color: #111827 !important; + transform: none !important; +} + +/* Nav */ +.pf-v5-c-nav__link { + font-weight: 900 !important; + text-transform: uppercase !important; + letter-spacing: 0.1em !important; + font-style: italic !important; + border-left: 4px solid transparent !important; + border-radius: 0 !important; +} + +.pf-v5-c-nav__link.pf-m-current, +.pf-v5-c-nav__link:hover { + border-left-color: #4f46e5 !important; + background-color: #fef9c3 !important; + color: #111827 !important; +} + +/* Alerts */ +.pf-v5-c-alert { + border: 4px solid #111827 !important; + border-radius: 0 !important; + box-shadow: 6px 6px 0 rgba(0, 0, 0, 1) !important; + font-weight: 800 !important; +} + +.pf-v5-c-alert.pf-m-success { + background-color: #bbf7d0 !important; +} +.pf-v5-c-alert.pf-m-warning { + background-color: #fde68a !important; +} +.pf-v5-c-alert.pf-m-danger { + background-color: #fecaca !important; +} +.pf-v5-c-alert.pf-m-info { + background-color: #c7d2fe !important; +} + +/* Tables */ +.pf-v5-c-table { + border: 4px solid #111827 !important; +} + +.pf-v5-c-table thead th { + background-color: #111827 !important; + color: #ffffff !important; + text-transform: uppercase !important; + font-weight: 900 !important; + letter-spacing: 0.1em !important; + font-style: italic !important; +} + +/* Links */ +a { + color: #4f46e5 !important; +} +a:hover { + color: #111827 !important; + text-decoration-thickness: 3px !important; +} diff --git a/themes/ecosplay/account/theme.properties b/themes/ecosplay/account/theme.properties new file mode 100644 index 0000000..1e0cd6e --- /dev/null +++ b/themes/ecosplay/account/theme.properties @@ -0,0 +1,4 @@ +parent=keycloak.v2 +import=common/keycloak +locales=fr,en +styles=css/account.css diff --git a/themes/ecosplay/email/html/template.ftl b/themes/ecosplay/email/html/template.ftl new file mode 100644 index 0000000..72626bf --- /dev/null +++ b/themes/ecosplay/email/html/template.ftl @@ -0,0 +1,52 @@ +<#macro emailLayout> + + + + + + E-Cosplay + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ // Authentification // E-Cosplay +
+

// Connexion sécurisée

+
+ <#nested> +
+
+ Communauté Inclusive // Hauts-de-France +
+ © E-Cosplay · www.e-cosplay.fr
+ Cet email vous a été envoyé suite à une action sur votre compte. Si vous n'êtes pas à l'origine de cette demande, ignorez ce message. +
+
+ + + diff --git a/themes/ecosplay/email/text/template.ftl b/themes/ecosplay/email/text/template.ftl new file mode 100644 index 0000000..eafbda2 --- /dev/null +++ b/themes/ecosplay/email/text/template.ftl @@ -0,0 +1,16 @@ +<#macro emailLayout> +========================================================= + // E-COSPLAY // CONNEXION SECURISEE +========================================================= + +<#nested> + +--------------------------------------------------------- +E-Cosplay - Communaute Inclusive - Hauts-de-France +https://www.e-cosplay.fr + +Cet email vous a ete envoye suite a une action sur votre +compte. Si vous n'etes pas a l'origine de cette demande, +ignorez ce message. +--------------------------------------------------------- + diff --git a/themes/ecosplay/email/theme.properties b/themes/ecosplay/email/theme.properties new file mode 100644 index 0000000..d66dbc3 --- /dev/null +++ b/themes/ecosplay/email/theme.properties @@ -0,0 +1,2 @@ +parent=keycloak +locales=fr,en