Skip to content

Latest commit

 

History

History
98 lines (78 loc) · 4.5 KB

README.md

File metadata and controls

98 lines (78 loc) · 4.5 KB

discourse-as-sso-erlang

Low-level erlang library to encode/decode payloads for using the forum software Discourse as an SSO endpoint.

Who is this For?

You want to use this library if you are building an application in Erlang and/or Elixir (or possibly LFE), and want to use the Discourse forum software as your user management system.

The Discourse development team has published a specification for using their software as an SSO endpoint in this post:

https://meta.discourse.org/t/using-discourse-as-a-sso-provider/32974.

This is NOT for the reverse case, where you have a Discourse forum and want to use another system as your single-sign-on.

This is a low-level library for generating the payload according to the specification in the above discussion (with hex encoded HMAC-Sha256 signatures), and has some helper methods for creating the URLs for redirecting. It is still up to you to save the nonce in your Erlang/Elixir application and to set your own cookies post validation.

Usage

There are four main API methods, of which two will be mainly used:

        as_formatted/3,
        get_sso_api_values/2,

        validate_sso_return_values/3,
        validate_query_string/2

The first two are for generating the payload to send to Discourse, and the last two methods are for validating the payload sent back from Discourse (i.e. to the return url that you specified).

-type discourse_host() :: string().                                                                                
-type nonce() :: string().                                                                                
-type redirect_url() :: string().                                                                                
-type return_url() :: string().                                                                                
-type key() :: string().                                                                                
-type query_string() :: binary().
-type user_nvs() :: #{}. 

Mostly, you will use as_formatted and validate_query_string. These methods wrap the other two, but handle creating (or decoding) URLs.

-spec as_formatted(discourse_host(), return_url(), key()) -> 
      {redirect_url(), nonce()}.  

It is up to you to re-direct. This library is not HTTP-aware. It is also up to you to store the nonce. This will be your lookup-key for when Discourse redirects back to the return_url().

-spec validate_query_string(query_string(), key()) ->
  invalid | {valid, nonce(), user_nvs()}.  

It is up to you to have an HTTP client (Cowboy?) listening at return_url() This library is not HTTP-aware. If parsed and valid, you will use the nonce that was encoded in the payload to lookup any stored values, etc, to know which request this is. You should probably set your own cookies, so as not to have to go back to Discourse for re-authentication.

The nonce that this library generates is a Crockford32-encoded random id. Not quite as rare as a UUID, but probably not going to hit you anytime in the next eon. Nonces are momentary anyways.

Examples:

Example of Encoding payload to send to Discourse:

2> discourse_as_sso_erlang:as_formatted("https://forum.wordadoplicus.com","https://wordadoplicus.com/return_url","mykey").

{"https://forum.wordadoplicus.com/session/sso_provider?sso=bm9uY2U9MWM1N2Fld3Y5NHQwYiZyZXR1cm5fc3NvX3VybD1odHRwczovL3dvcmRhZG9wbGljdXMuY29tL3JldHVybl91cmw%3D&sig=ee050c6e5e3a532a386c99d4c177c49254abd547f397e137a2bfd2fe116b5cac",
 "1c57aewv94t0b"}

Example of Decoding return values from Discourse:

16> discourse_as_sso_erlang:validate_query_string(<<"sso=bm9uY2U9MWM1MzR0YmJxbTBnZyZuYW1lPURhbmllbG9wb2RvbiZ1c2VybmFt%0AZT13b3JkYWRvcGxpY3VzLWFkbWluJmVtYWlsPXNlcnZpY2UlNDB3b3JkYWRv%0AcGxpY3VzLmNvbSZleHRlcm5hbF9pZD0xJnJldHVybl9zc29fdXJsPWh0dHBz%0AJTNBJTJGJTJGd29yZGFkb3BsaWN1cy5jb20lMkZib29vJmFkbWluPXRydWUm%0AbW9kZXJhdG9yPWZhbHNl%0A&sig=0e59abaca0a6ec881d91d54ad8ce8feab65acebd467b28e7361a2c9dc822fc73">>,"wacopacotaco").
{valid,"1c534tbbqm0gg",
       #{<<"admin">> => <<"true">>,
         <<"email">> => <<"[email protected]">>,
         <<"external_id">> => <<"1">>,
         <<"moderator">> => <<"false">>,
         <<"name">> => <<"Danielopodon">>,
         <<"nonce">> => <<"1c534tbbqm0gg">>,
         <<"return_sso_url">> => <<"https://wordadoplicus.com/booo">>,
         <<"username">> => <<"wordadoplicus-admin">>}}