Samly - Add SAML SSO to your Phoenix application (now with multiple identity provider support)

Created a blog post on using samly. This includes instructions on setting up a self-hosted Shibboleth SAML Identity Provider that uses OpenLDAP.


Samly V0.9.0 - IDP Initiated Login (aka IDP-First flow)

The authentication flow can now be started from an IDP. For example, cloud hosted SAML authentication providers such as OneLogin allow your application to be registered and be shown on an application portal/dashboard. The end user can login to the application portal click on your application Icon and be redirected/taken to your application.

Samly already supports the SP initiated login flow. In this model, the end user visits your application pages first. The login flow is initiated in your application, user authenticates and gets redirected back to your app.

Based on how your IDP is setup, you can get the user profile information along with any assigned “roles” in the SAML assertion. These are made available for you in the Plug/Phoenix connection. You can use any plug based authorization system to perform authorizations.

FYI. Samly is known to work with SimpleSAMLPhp, Shibboleth, OneLogin and other SAML 2.0 providers. If you work with other SAML providers, use the documentation and the blog entry above to do your own integration. Please share if you are able to integrate Samly with other SAML providers.

Really impressed how you’re bringing Samly along. I have a project coming up that will absolutely benefit from your work. Part of that will be doing some work to integrate with SAP’s IDP. Thanks for the effort!

Hope this can evolve to work with more providers. When you are ready, let us know how it goes with SAP IDP. Thanks.

Please i’m having issue getting this to work in my phoenix app. I have installed as stated in the readme details.

Below is what my config looks like

config :samly, Samly.Provider,
  idp_id_from: :path_segment,
  service_providers: [
      id: "entsp",
      certfile: "priv/keys/samly.crt",
      keyfile: "priv/keys/samly.pem"
  identity_providers: [
      id: "entidp",
      sp_id: "entsp",
      metadata_file: "idp_metadata.xml"

While testing the login with the link http://localhost:4000/sso/auth/signin/entidp, i got Argument error

[error] #PID<0.704.0> running EnterpriseWeb.Endpoint (cowboy_protocol) terminated
Server: localhost:4000 (http)
Request: POST /sso/auth/signin/entidp
** (exit) an exception was raised:
    ** (ArgumentError) argument error
        (xmerl) xmerl_lib.erl:69: :xmerl_lib.export_text/2
        (xmerl) xmerl.erl:191: :xmerl.export_content/2
        (xmerl) xmerl.erl:224: :xmerl.export_element/2
        (xmerl) xmerl.erl:199: :xmerl.export_content/2
        (xmerl) xmerl.erl:199: :xmerl.export_content/2
        (xmerl) xmerl.erl:224: :xmerl.export_element/2
        (xmerl) xmerl.erl:199: :xmerl.export_content/2
        (xmerl) xmerl.erl:168: :xmerl.export1/3
        (esaml) /Library/WebServer/Documents/enterprise/deps/esaml/src/esaml_binding.erl:77: :esaml_binding.encode_http_post/3
        (samly) lib/samly/router_util.ex:94: Samly.RouterUtil.send_saml_request/5
        (samly) lib/samly/auth_router.ex:1: Samly.AuthRouter.plug_builder_call/2
        (plug) lib/plug/router/utils.ex:92: Plug.Router.Utils.forward/4
        (samly) lib/samly/router.ex:1: Samly.Router.plug_builder_call/2
        (phoenix) lib/phoenix/router/route.ex:147: Phoenix.Router.Route.forward/4
        (phoenix) lib/phoenix/router.ex:278: Phoenix.Router.__call__/1
        (enterprise) lib/enterprise_web/endpoint.ex:1: EnterpriseWeb.Endpoint.plug_builder_call/2
        (enterprise) lib/plug/debugger.ex:102: EnterpriseWeb.Endpoint."call (overridable 3)"/2
        (enterprise) lib/enterprise_web/endpoint.ex:1:
        (plug) lib/plug/adapters/cowboy/handler.ex:16: Plug.Adapters.Cowboy.Handler.upgrade/4

Please how can i resolve this? Thanks.

Sounds to me like whatever SSO server you are using is missing a required field, should set the SSO server to export that field, or PR Saml to not require whatever that field is. :slight_smile:

/me built their own SSO client since our new work SSO server gives a username… and that’s it, nothing else…

1 Like

Thanks immensely @OvermindDL1. I don’t think the problem is from the SSO server because the request hasn’t been sent at the time this error shows up.

resp_body = :esaml_binding.encode_http_post(idp_url, signed_xml_payload, relay_state) from the function below throws that error.

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)
      resp_body = :esaml_binding.encode_http_post(idp_url, signed_xml_payload, relay_state)

      |> Conn.put_resp_header("Content-Type", "text/html")
      |> Conn.send_resp(200, resp_body)


The error is gone after adding entity_id to the service provider confirguration.

1 Like

Please i observe the idp_metadata file linked in the configuration is not being used. Saml seems to be generating a separate idp_metadata content. I navigated to http://localhost:4000/sso/sp/metadata/entidp and the details of the metadata is different from the the linked idp_metadata.

Please is there a way to enforce the metadata that is used?

1 Like

@handnot2 please can you kindly update the name_format in the function below to use the nameid_format property provided in the idp configuration?


def gen_idp_signin_req(sp, idp_metadata) do
    idp_signin_url = Esaml.esaml_idp_metadata(idp_metadata, :login_location)
    # TODO: Expose an config
    name_format = 'urn:oasis:names:tc:SAML:2.0:nameid-format:transient'
    xml_frag = :esaml_sp.generate_authn_request(idp_signin_url, sp, name_format)
    {idp_signin_url, xml_frag}


Has anyone already integrated samly successfully with an ADFS IdP? I may need soon to support SSO with ADFS and just started evaluating the different solutions.

1 Like

@handnot2 Attempting to follow the guide for:

But when I run the docker container and hit http://localhost:8082/simplesaml/

I get:

**Parse error** : syntax error, unexpected end of file in  **/srv/simplesaml/config/config.php**  on line  **56**

**Fatal error** : Exception thrown without a stack frame in  **Unknown**  on line  **0**

Am I doing something terribly wrong or is an underlying package with the PHP setup not playing well maybe?


Let me check and get back in a day or two.

SimpleSAMLphp IdP Docker Container

samly_simplesaml (v0.3)

Moved up to the latest SimpleSAMLphp release Version 1.16.2. Updated the parameters and config templates to match this version of SimpleSAMLphp. You will have to rebuild the docker image. Make sure to update to the latest version of docker-ce and docker-compose.

docker-compose up -d
sleep 5
docker-compose down
docker-compose up -d

It should work without any config errors with this update.

1 Like

Awesome, thanks!
I will check it out! :slight_smile:

Sorry if I’m missing something simple, and I’ve searched for existing topics on Samly and Phoenix 1.4, but I’m getting errors with the instructions to set this up. I am currently on:

  • Elixir 1.7.4 (compiled with Erlang/OTP 21)
  • Erlang/OTP 21
  • Windows 10 Pro x64 (version 1803)

And my Phoenix app’s deps are:
{:phoenix, “~> 1.4.0”},
{:phoenix_pubsub, “~> 1.1”},
{:phoenix_ecto, “~> 4.0”},
{:ecto_sql, “~> 3.0”},
{:postgrex, “>= 0.0.0”},
{:phoenix_html, “~> 2.11”},
{:phoenix_live_reload, “~> 1.2”, only: :dev},
{:gettext, “~> 0.11”},
{:jason, “~> 1.0”},
{:plug_cowboy, “~> 2.0”},
{:samly, “~> 0.9”}

When I run mix deps.get, I get the output:
?[4mFailed to use “cowboy” (version 2.6.1) because?[0m
?[1mesaml (versions 3.4.0 to 3.6.1)?[0m requires ?[31m1.1.2?[0m
?[1mplug_cowboy (version 2.0.0)?[0m requires ?[32m~> 2.5?[0m
?[1mmix.lock?[0m specifies ?[32m2.6.1?[0m
** (Mix) Hex dependency resolution failed, change the version requirements of your dependencies or unlock them (by using mix deps.update or mix deps.unlock). If you are unable to resolve the conflicts you can try overriding with {:dependency, “~> 1.0”, override: true}

I am brand-new to Phoenix so it might just be me, but it looks like there are version issues with plug_cowboy? However, if I try to add “override: true” I still get the error. From what I can tell the problem is specifically with the dependencies of esaml, but I’m not sure. I’m happy to contribute to this if I can get pointed in the right direction. Thoughts? Thanks in advance!

Haven’t checked Samly with Phoenix 1.4 and cowboy 2.0. Not sure if there are any compatibility problems. Please open an issue in the Samly Repo.

Can you check it out with Phoenix 1.3 and cowboy/plug_cowboy 1.x?

Thanks so much for the quick response. After struggling to get it to resolve for Phoenix 1.4, for now I am going to instead look at Gravitee.IO (which uses OpenID Connect) since it looks like it has an up-to-date, officially supported package. If I do ultimately decide to go back to SAML I’ll let you know what I find. Cheers!

Does SAMLY care what format the certificate files are in?

I’m trying to integrate with ADFS, I’m getting some errors.

ID6013: The signature verification failed.
ID6018: Digest verification failed for reference ‘#id1543437817381650518114’.

verifying w/ the .crt is working

A potential culprit is that UNIX build step using OpenSSL is created a Unix style line breaks that Powershell is not reading correctly.

One thought I’ve had was to generate .pfx from .pem.

However as I’m in the dark on much of this, I am only guessing that it might assist the blocker I have.

If you think the unix generated file with line endings is causing the issue, I suggest trying PuTTYgen on windows to generate the key and certificate files.

Hopefully someone one the forum pitches in to help with generating self signed cert and importing the cert in ADFS.