From 9cab36727e4921b17255b1f7373bb68ba759b35f Mon Sep 17 00:00:00 2001 From: BluemediaGER <oliver@traber-info.de> Date: Mon, 20 Feb 2023 19:23:16 +0100 Subject: [PATCH 1/2] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b453f73..9ca0341 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # A modern Keycloak login theme -keycloak-modern-login is a Keycloak login theme that's build using Vue.js 3 and Typescript. It is easily extensible and bypasses the complexity of FreeMarker templates. +keycloak-modern-login is a Keycloak login theme that's build using Tailwind CSS, Vue.js 3 and Typescript. It is easily extensible and bypasses the complexity of FreeMarker templates. <details> <summary>Screenshots</summary> From 7a0edc13766a347187eb9177dfbccd3b8210ff50 Mon Sep 17 00:00:00 2001 From: BluemediaGER <oliver@traber-info.de> Date: Mon, 20 Feb 2023 22:50:54 +0100 Subject: [PATCH 2/2] Add custom saml-post-form --- README.md | 3 +- src/types/context.ts | 10 ++++ src/types/samlPostData.ts | 5 ++ src/views/saml-post-form/index.ftl | 6 +++ src/views/saml-post-form/index.ts | 7 +++ src/views/saml-post-form/index.vue | 65 +++++++++++++++++++++++ src/views/webauthn-authenticate/index.vue | 2 +- webpack.config.js | 2 +- 8 files changed, 97 insertions(+), 3 deletions(-) create mode 100644 src/types/samlPostData.ts create mode 100644 src/views/saml-post-form/index.ftl create mode 100644 src/views/saml-post-form/index.ts create mode 100644 src/views/saml-post-form/index.vue diff --git a/README.md b/README.md index 9ca0341..5c73e9d 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,8 @@ keycloak-modern-login is a Keycloak login theme that's build using Tailwind CSS,  - + + </details> ## State of this project diff --git a/src/types/context.ts b/src/types/context.ts index f33a8a3..1a7c3a8 100644 --- a/src/types/context.ts +++ b/src/types/context.ts @@ -325,6 +325,16 @@ export declare namespace KcContextBase { attributesByName: Record<string, Attribute>; }; }; + + export type SAMLPostForm = Common & { + pageId: "saml-post-form.ftl" + samlPost: { + url: string; + SAMLRequest?: string; + SAMLResponse?: string; + relayState?: string; + } + }; } export type Attribute = { diff --git a/src/types/samlPostData.ts b/src/types/samlPostData.ts new file mode 100644 index 0000000..6bc70c3 --- /dev/null +++ b/src/types/samlPostData.ts @@ -0,0 +1,5 @@ +export type SAMLPostData = { + SAMLRequest?: string, + SAMLResponse?: string, + relayState?: string, +} \ No newline at end of file diff --git a/src/views/saml-post-form/index.ftl b/src/views/saml-post-form/index.ftl new file mode 100644 index 0000000..21397e4 --- /dev/null +++ b/src/views/saml-post-form/index.ftl @@ -0,0 +1,6 @@ +<#import "baselayout.ftl" as layout> +<@layout.baseLayout pageId="saml-post-form.ftl" ; section> + <#if section = "scripts"> + <script typo="module" src="${url.resourcesPath}/js/saml-post-form.js"></script> + </#if> +</@layout.baseLayout> diff --git a/src/views/saml-post-form/index.ts b/src/views/saml-post-form/index.ts new file mode 100644 index 0000000..9344ee4 --- /dev/null +++ b/src/views/saml-post-form/index.ts @@ -0,0 +1,7 @@ +import { createApp } from "vue"; +import index from "./index.vue"; + +if ((window as any).kcContext) { + const app = createApp(index); + app.mount("#app"); +} diff --git a/src/views/saml-post-form/index.vue b/src/views/saml-post-form/index.vue new file mode 100644 index 0000000..e5ea71e --- /dev/null +++ b/src/views/saml-post-form/index.vue @@ -0,0 +1,65 @@ +<template> + <layout> + <div class="flex justify-center justify-items-center"> + <svg class="h-15 w-15 animate-spin" preserveAspectRatio="xMidYMid"> + <circle cx="50%" cy="50%" r="35" fill="none" stroke="#374151" stroke-width="10" stroke-dasharray="164 56"/> + </svg> + </div> + <h1 class="mt-4 text-xl text-center text-gray-700">Redirecting...</h1> + </layout> +</template> +<script lang="ts"> +import { defineComponent } from "vue"; +import Layout from "~/components/Layout.vue"; +import type { KcContextBase } from "~/types/context"; +import type { SAMLPostData } from "~/types/samlPostData" + +export default defineComponent({ + name: "SamlPostForm", + components: { + Layout, + }, + data() { + return { + context: (window as any).kcContext as KcContextBase.SAMLPostForm, + }; + }, + mounted: function () { + const postData: SAMLPostData = { + SAMLRequest: this.context.samlPost.SAMLRequest, + SAMLResponse: this.context.samlPost.SAMLResponse, + relayState: this.context.samlPost.relayState, + }; + this.formPost(this.context.samlPost.url, postData); + }, + methods: { + formPost(url: string, data: object) { + const form = document.createElement("form"); + form.method = "post"; + form.action = url; + + for (const key in data) { + if (Object.prototype.hasOwnProperty.call(data, key)) { + if (data[key] === undefined) { + continue; + } + + const hiddenField = document.createElement("input"); + hiddenField.type = "hidden"; + hiddenField.name = key; + hiddenField.value = data[key]; + + form.appendChild(hiddenField); + } + } + document.body.appendChild(form); + form.submit(); + }, + }, +}); +</script> +<style> +@tailwind base; +@tailwind components; +@tailwind utilities; +</style> diff --git a/src/views/webauthn-authenticate/index.vue b/src/views/webauthn-authenticate/index.vue index e433d12..ed6a2e8 100644 --- a/src/views/webauthn-authenticate/index.vue +++ b/src/views/webauthn-authenticate/index.vue @@ -86,7 +86,7 @@ import type { KcContextBase } from "~/types/context"; import { base64url } from "rfc4648"; export default defineComponent({ - name: "Login", + name: "WebAuthnAuthenticate", components: { Layout, ErrorBox, diff --git a/webpack.config.js b/webpack.config.js index 5807125..ba34e35 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -5,7 +5,7 @@ const { CleanWebpackPlugin } = require("clean-webpack-plugin"); const CopyWebpackPlugin = require("copy-webpack-plugin"); const THEME_NAME = "modern-login"; -const customPages = ["login", "webauthn-authenticate"]; +const customPages = ["login", "webauthn-authenticate", "saml-post-form"]; module.exports = function (env, argv) { const isDevelopment = argv.mode !== "production";