Packages
samly
1.0.0
1.4.0
1.3.0
1.2.0
1.1.0
1.0.0
1.0.0-rc.1
retired
1.0.0-rc.0
retired
0.10.1
retired
0.10.0
retired
0.9.3
retired
0.9.2
retired
0.9.1
retired
0.9.0
retired
0.8.4
retired
0.8.3
retired
0.8.2
retired
0.8.1
retired
0.8.0
retired
0.7.2
retired
0.7.1
retired
0.7.0
retired
0.6.3
retired
0.6.2
retired
0.6.1
retired
0.6.0
retired
0.5.0
retired
0.4.0
retired
0.1.2
retired
SAML Single-Sign-On Authentication for Plug/Phoenix Applications
Current section
Files
Jump to
Current section
Files
lib/samly/router_util.ex
defmodule Samly.RouterUtil do
@moduledoc false
alias Plug.Conn
require Logger
require Samly.Esaml
alias Samly.{Esaml, IdpData, Helper}
@subdomain_re ~r/^(?<subdomain>([^.]+))?\./
def check_idp_id(conn, _opts) do
idp_id_from = Application.get_env(:samly, :idp_id_from)
idp_id =
if idp_id_from == :subdomain do
case Regex.named_captures(@subdomain_re, conn.host) do
%{"subdomain" => idp_id} -> idp_id
_ -> nil
end
else
case conn.params["idp_id_seg"] do
[idp_id] -> idp_id
_ -> nil
end
end
idp = idp_id && Helper.get_idp(idp_id)
if idp do
conn |> Conn.put_private(:samly_idp, idp)
else
conn |> Conn.send_resp(403, "invalid_request unknown IdP") |> Conn.halt()
end
end
def check_target_url(conn, _opts) do
try do
target_url = conn.params["target_url"] && URI.decode_www_form(conn.params["target_url"])
conn |> Conn.put_private(:samly_target_url, target_url)
rescue
ArgumentError ->
Logger.error(
"[Samly] target_url must be x-www-form-urlencoded: #{inspect(conn.params["target_url"])}"
)
conn |> Conn.send_resp(400, "target_url must be x-www-form-urlencoded") |> Conn.halt()
end
end
# generate URIs using the idp_id
@spec ensure_sp_uris_set(tuple, Conn.t()) :: tuple
def ensure_sp_uris_set(sp, conn) do
case Esaml.esaml_sp(sp, :metadata_uri) do
[?/ | _] ->
uri = %URI{
scheme: Atom.to_string(conn.scheme),
host: conn.host,
port: conn.port,
path: "/sso"
}
base_url = URI.to_string(uri)
idp_id_from = Application.get_env(:samly, :idp_id_from)
path_segment_idp_id =
if idp_id_from == :subdomain do
nil
else
%IdpData{id: idp_id} = conn.private[:samly_idp]
idp_id
end
Esaml.esaml_sp(
sp,
metadata_uri: Helper.get_metadata_uri(base_url, path_segment_idp_id),
consume_uri: Helper.get_consume_uri(base_url, path_segment_idp_id),
logout_uri: Helper.get_logout_uri(base_url, path_segment_idp_id)
)
_ ->
sp
end
end
def send_saml_request(conn, idp_url, use_redirect?, signed_xml_payload, relay_state) do
if use_redirect? do
url =
:esaml_binding.encode_http_redirect(idp_url, signed_xml_payload, :undefined, relay_state)
conn |> redirect(302, url)
else
nonce = conn.private[:samly_nonce]
resp_body = :esaml_binding.encode_http_post(idp_url, signed_xml_payload, relay_state, nonce)
conn
|> Conn.put_resp_header("content-type", "text/html")
|> Conn.send_resp(200, resp_body)
end
end
def redirect(conn, status_code, dest) do
conn
|> Conn.put_resp_header("location", URI.encode(dest))
|> Conn.send_resp(status_code, "")
|> Conn.halt()
end
end