diff --git a/extra/lib/plausible_web/sso/real_saml_adapter.ex b/extra/lib/plausible_web/sso/real_saml_adapter.ex index da5480d3e1..509d7f2c60 100644 --- a/extra/lib/plausible_web/sso/real_saml_adapter.ex +++ b/extra/lib/plausible_web/sso/real_saml_adapter.ex @@ -3,7 +3,6 @@ defmodule PlausibleWeb.SSO.RealSAMLAdapter do Real implementation of SAML authentication interface. """ alias Plausible.Auth.SSO - alias SimpleXml.XmlNode alias PlausibleWeb.Router.Helpers, as: Routes @@ -86,7 +85,7 @@ defmodule PlausibleWeb.SSO.RealSAMLAdapter do public_key = X509.Certificate.public_key(cert), :ok <- SimpleSaml.verify_and_validate_response(root, assertion, public_key, @verify_opts), - {:ok, attributes} <- extract_attributes(root) do + {:ok, attributes} <- extract_attributes(assertion) do session_timeout_minutes = integration.team.policy.sso_session_timeout_minutes expires_at = @@ -128,49 +127,33 @@ defmodule PlausibleWeb.SSO.RealSAMLAdapter do |> String.trim() end - defp extract_attributes(root_node) do - with {:ok, assertion_node} <- XmlNode.first_child(root_node, ~r/.*:?Assertion$/), - {:ok, attributes_node} <- - XmlNode.first_child(assertion_node, ~r/.*:?AttributeStatement$/), - {:ok, attribute_nodes} <- XmlNode.children(attributes_node) do - found = get_attributes(attribute_nodes) + defp extract_attributes(assertion) do + attributes = + Enum.reduce([:email, :first_name, :last_name], %{}, fn field, attrs -> + value = + assertion.attributes + |> Map.get(to_string(field), []) + |> List.first() - attributes = %{ - email: String.trim(found["email"] || ""), - first_name: String.trim(found["first_name"] || ""), - last_name: String.trim(found["last_name"] || "") - } + Map.put(attrs, field, String.trim(value || "")) + end) - cond do - attributes.email == "" -> - {:error, :missing_email_attribute} + cond do + attributes.email == "" -> + {:error, :missing_email_attribute} - # very rudimentary way to check if the attribute is at least email-like - not String.contains?(attributes.email, "@") or String.length(attributes.email) < 3 -> - {:error, :invalid_email_attribute} + # very rudimentary way to check if the attribute is at least email-like + not String.contains?(attributes.email, "@") or String.length(attributes.email) < 3 -> + {:error, :invalid_email_attribute} - attributes.first_name == "" and attributes.last_name == "" -> - {:error, :missing_name_attributes} + attributes.first_name == "" and attributes.last_name == "" -> + {:error, :missing_name_attributes} - true -> - {:ok, attributes} - end + true -> + {:ok, attributes} end end - defp get_attributes(nodes) do - Enum.reduce(nodes, %{}, fn node, attributes -> - with {:ok, name} <- XmlNode.attribute(node, "Name"), - {:ok, value_node} <- XmlNode.first_child(node, ~r/.*:?AttributeValue$/), - {:ok, value} <- XmlNode.text(value_node) do - Map.put(attributes, name, value) - else - _ -> - attributes - end - end) - end - defp safe_decode_www_form(nil), do: "" defp safe_decode_www_form(data), do: URI.decode_www_form(data) diff --git a/mix.exs b/mix.exs index d6e8527a09..c745bb23a2 100644 --- a/mix.exs +++ b/mix.exs @@ -114,7 +114,6 @@ defmodule Plausible.MixProject do {:plug, "~> 1.13", override: true}, {:plug_cowboy, "~> 2.3"}, {:polymorphic_embed, "~> 5.0"}, - {:x509, "~> 0.8.10"}, {:postgrex, "~> 0.19.0"}, {:prom_ex, "~> 1.8"}, {:peep, "~> 3.4"}, @@ -122,7 +121,7 @@ defmodule Plausible.MixProject do {:ref_inspector, "~> 2.0"}, {:referrer_blocklist, git: "https://github.com/plausible/referrer-blocklist.git"}, {:sentry, "~> 10.8.1"}, - {:simple_saml, git: "https://github.com/MBXSystems/simple_saml.git", branch: "main"}, + {:simple_saml, "~> 1.2"}, {:xml_builder, "~> 2.1"}, {:siphash, "~> 3.2"}, {:timex, "~> 3.7"}, diff --git a/mix.lock b/mix.lock index 8ec0f17f2d..cdefca7ee4 100644 --- a/mix.lock +++ b/mix.lock @@ -139,14 +139,14 @@ "referrer_blocklist": {:git, "https://github.com/plausible/referrer-blocklist.git", "d6f52c225cccb4f04b80e3a5d588868ec234139d", []}, "req": {:hex, :req, "0.5.6", "8fe1eead4a085510fe3d51ad854ca8f20a622aae46e97b302f499dfb84f726ac", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "cfaa8e720945d46654853de39d368f40362c2641c4b2153c886418914b372185"}, "rustler_precompiled": {:hex, :rustler_precompiled, "0.7.3", "42cb9449785cd86c87453e39afdd27a0bdfa5c77a4ec5dc5ce45112e06b9f89b", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:rustler, "~> 0.23", [hex: :rustler, repo: "hexpm", optional: true]}], "hexpm", "cbc4b3777682e5f6f43ed39b0e0b4a42dccde8053aba91b4514e8f5ff9a5ac6d"}, - "saxy": {:hex, :saxy, "1.5.0", "0141127f2d042856f135fb2d94e0beecda7a2306f47546dbc6411fc5b07e28bf", [:mix], [], "hexpm", "ea7bb6328fbd1f2aceffa3ec6090bfb18c85aadf0f8e5030905e84235861cf89"}, + "saxy": {:hex, :saxy, "1.6.0", "02cb4e9bd045f25ac0c70fae8164754878327ee393c338a090288210b02317ee", [:mix], [], "hexpm", "ef42eb4ac983ca77d650fbdb68368b26570f6cc5895f0faa04d34a6f384abad3"}, "scrivener": {:hex, :scrivener, "2.7.2", "1d913c965ec352650a7f864ad7fd8d80462f76a32f33d57d1e48bc5e9d40aba2", [:mix], [], "hexpm", "7866a0ec4d40274efbee1db8bead13a995ea4926ecd8203345af8f90d2b620d9"}, "scrivener_ecto": {:hex, :scrivener_ecto, "2.7.0", "cf64b8cb8a96cd131cdbcecf64e7fd395e21aaa1cb0236c42a7c2e34b0dca580", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:scrivener, "~> 2.4", [hex: :scrivener, repo: "hexpm", optional: false]}], "hexpm", "e809f171687806b0031129034352f5ae44849720c48dd839200adeaf0ac3e260"}, "sentry": {:hex, :sentry, "10.8.1", "aa45309785e1521416225adb16e0b4d8b957578804527f3c7babb6fefbc5e456", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:nimble_options, "~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_ownership, "~> 0.3.0 or ~> 1.0", [hex: :nimble_ownership, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, "~> 0.20 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.6", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "495b3cdadad90ba72eef973aa3dec39b3b8b2a362fe87e2f4ef32133ac3b4097"}, - "simple_saml": {:git, "https://github.com/MBXSystems/simple_saml.git", "d161dbc6cc059bddccdc986a0e1b29823e4348fd", [branch: "main"]}, - "simple_xml": {:hex, :simple_xml, "1.3.1", "66813a84f650c4ac041ac9b0497d35448cadc5826a6d71a4dd2a33f015f48197", [:mix], [{:saxy, "~> 1.5", [hex: :saxy, repo: "hexpm", optional: false]}, {:x509, "~> 0.8.7", [hex: :x509, repo: "hexpm", optional: false]}], "hexpm", "67dc14276a7f71bdb868f345e0d63e52db49da54521cb43eb2c7aac67ef7147d"}, + "simple_saml": {:hex, :simple_saml, "1.2.0", "d875939e21cd73cdb3f747e701e4d2d5f0f4e35610d37df50629087454fa43f9", [:mix], [{:simple_xml, "~> 1.3", [hex: :simple_xml, repo: "hexpm", optional: false]}, {:x509, "~> 0.9.0", [hex: :x509, repo: "hexpm", optional: false]}], "hexpm", "24663665e53a91bfc38359ed9f26f575a389bde9fc94ec369f9f2259046feaf0"}, + "simple_xml": {:hex, :simple_xml, "1.3.2", "84b892527b5183748694583a658c729c84bb89fc8ac650d7025ebc2c49e74018", [:mix], [{:saxy, "~> 1.5", [hex: :saxy, repo: "hexpm", optional: false]}, {:x509, "~> 0.9.0", [hex: :x509, repo: "hexpm", optional: false]}], "hexpm", "8c15fa49955a8c82b50f3053617e8a4cd771fcd0a502d660e56993c38ac86ca5"}, "siphash": {:hex, :siphash, "3.2.0", "ec03fd4066259218c85e2a4b8eec4bb9663bc02b127ea8a0836db376ba73f2ed", [:make, :mix], [], "hexpm", "ba3810701c6e95637a745e186e8a4899087c3b079ba88fb8f33df054c3b0b7c3"}, - "site_encrypt": {:git, "https://github.com/sasa1977/site_encrypt.git", "046fbeca11b889604dafd2df6a71001f8abe5e2c", []}, + "site_encrypt": {:git, "https://github.com/sasa1977/site_encrypt.git", "8d47801c51eeea11ac385cb73eef4ed9a6565367", []}, "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"}, "tailwind": {:hex, :tailwind, "0.2.2", "9e27288b568ede1d88517e8c61259bc214a12d7eed271e102db4c93fcca9b2cd", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "ccfb5025179ea307f7f899d1bb3905cd0ac9f687ed77feebc8f67bdca78565c4"}, @@ -161,7 +161,7 @@ "unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, "websock_adapter": {:hex, :websock_adapter, "0.5.8", "3b97dc94e407e2d1fc666b2fb9acf6be81a1798a2602294aac000260a7c4a47d", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "315b9a1865552212b5f35140ad194e67ce31af45bcee443d4ecb96b5fd3f3782"}, - "x509": {:hex, :x509, "0.8.10", "5d1ec6d5f4db31982f9dc34e6a1eebd631d04599e0b6c1c259f1dadd4495e11f", [:mix], [], "hexpm", "a191221665af28b9bdfff0c986ef55f80e126d8ce751bbdf6cefa846410140c0"}, + "x509": {:hex, :x509, "0.9.1", "c92026a17b7d93f19029842ca218f82ec1f1e7cc9d4aa0c48327ee778f7f482e", [:mix], [], "hexpm", "99328951a1480cfd7b1b8aa688f857f7f5bbea03077b78cad211fb3b30c2f4a8"}, "xml_builder": {:hex, :xml_builder, "2.4.0", "b20d23077266c81f593360dc037ea398461dddb6638a329743da6c73afa56725", [:mix], [], "hexpm", "833e325bb997f032b5a1b740d2fd6feed3c18ca74627f9f5f30513a9ae1a232d"}, "yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"}, "zstream": {:hex, :zstream, "0.6.5", "ad4c5631f0da986ddcf8b23d0d2c696c09cedb1c3ace027fb2312a809df6f8b8", [:mix], [], "hexpm", "de908d8a050f6aabf5f4931aa41dab49419e3c8b95cfee01461a8c84fdde005e"},