Re: [Snowdrift-dev] [PATCH] Discourse SSO support
Thanks for this. I think the best way to make use of this is to package up the logic specific to handling SSO requests in an independent library, so we can use it later. That's not about you, or about this code. :) It's just that I am going to push back hard on having SSO be the second major feature we add to our website (or the third, or even the tenth). We'll see where that discussion goes. On Mon, Dec 05, 2016 at 04:13:42AM +0200, fr33domlover wrote: > From: fr33domlover > > --- > website/Snowdrift.cabal | 7 > website/config/routes| 2 ++ > website/config/settings.yml | 4 +++ > website/src/Application.hs | 1 + > website/src/Discourse.hs | 73 > > website/src/Handler/Discourse.hs | 55 ++ > website/src/Settings.hs | 4 +++ > 7 files changed, 146 insertions(+) > create mode 100644 website/src/Discourse.hs > create mode 100644 website/src/Handler/Discourse.hs > > diff --git a/website/Snowdrift.cabal b/website/Snowdrift.cabal > index 9c1664c..b5cfaa5 100644 > --- a/website/Snowdrift.cabal > +++ b/website/Snowdrift.cabal > @@ -40,6 +40,7 @@ library > Avatar > Application > Css > +Discourse > Email > Foundation > Import > @@ -49,6 +50,7 @@ library > Settings.StaticFiles > Handler > Handler.Dashboard > +Handler.Discourse > Handler.PaymentInfo > Handler.Pledge > Handler.Project > @@ -74,6 +76,7 @@ library > , bytestring >= 0.9 && < 0.11 > , classy-prelude >= 0.10.2 > , classy-prelude-yesod >= 0.10.2 > +, cryptonite > , data-default > , errors > , esqueleto > @@ -82,8 +85,10 @@ library > , formattable > , hjsmin >= 0.1 > , http-client > +, http-types > , lens > , libravatar > +, memory > , mime-mail > , monad-logger >= 0.3 && < 0.4 > , nonce > @@ -99,6 +104,7 @@ library > , text >= 0.11&& < 2.0 > , time > , titlecase > +, transformers > , unordered-containers > , wai > , wai-extra >= 3.0 && < 3.1 > @@ -122,6 +128,7 @@ library > RecordWildCards > ScopedTypeVariables > TemplateHaskell > +TupleSections > TypeFamilies > ViewPatterns > > diff --git a/website/config/routes b/website/config/routes > index 9e4e079..30fdef8 100644 > --- a/website/config/routes > +++ b/website/config/routes > @@ -26,6 +26,8 @@ > /p/snowdrift SnowdriftProjectR GET > /pledge/snowdrift PledgeSnowdriftR POST DELETE > > +/discourse/sso DiscourseR GET > + > -- ## Backward compatibility routes > > -- Prevents breakage of external links to the old wiki. See > diff --git a/website/config/settings.yml b/website/config/settings.yml > index 3c30c0f..e4e30bb 100644 > --- a/website/config/settings.yml > +++ b/website/config/settings.yml > @@ -44,3 +44,7 @@ send-email: "_env:SD_EMAILS:false" > # chreekat for assistance. > stripe-secret-key: "_env:STRIPE_SECRET_KEY:" > stripe-publishable-key: "_env:STRIPE_PUBLISHABLE_KEY:" > + > +# Discourse SSO > +discourse-url: "https://discourse.snowdrift.coop"; > +discourse-sso-secret: "" > diff --git a/website/src/Application.hs b/website/src/Application.hs > index 8ccd6b2..761d3f8 100644 > --- a/website/src/Application.hs > +++ b/website/src/Application.hs > @@ -35,6 +35,7 @@ import qualified Yesod.GitRev as G > > import Handler > import Handler.Dashboard > +import Handler.Discourse > import Handler.PaymentInfo > import Handler.Pledge > import Handler.Project > diff --git a/website/src/Discourse.hs b/website/src/Discourse.hs > new file mode 100644 > index 000..cca0bb1 > --- /dev/null > +++ b/website/src/Discourse.hs > @@ -0,0 +1,73 @@ > +module Discourse where > + > +import Prelude > + > +import Crypto.Hash.Algorithms (SHA256) > +import Crypto.MAC.HMAC > +import Data.ByteArray.Encoding > +import Data.ByteString (ByteString) > +import Data.Maybe (catMaybes) > +import Data.Text (Text, pack) > +import Data.Text.Encoding (encodeUtf8) > +import Network.HTTP.Types.URI (renderSimpleQuery) > + > +import qualified Data.ByteString as B (drop) > + > +import Model > + > +-- | Information we send back to Discourse once the user logs in through our > +-- UI. > +data UserInfo = UserInfo > +{ ssoEmail :: Text > +, ssoId:: UserId > +, ssoUsername :: Maybe Text > +, ssoFullName :: Maybe Text > +, ssoAvatarUrl :: Maybe Text > +, ssoBio :: Maybe Text > +} > + > +-- | Type restricted convenience wrapper that computes our HMAC. > +hmacSHA256 :: ByteString -> ByteString -> HMAC SHA256 > +hmacSHA256 = hmac > + > +-- | Given secret known in advance and pay
Re: [Snowdrift-dev] [PATCH] Discourse SSO support
On 12/05/2016 11:34 AM, Bryan Richter wrote: > Thanks for this. I think the best way to make use of this is to package > up the logic specific to handling SSO requests in an independent > library, so we can use it later. > > That's not about you, or about this code. :) It's just that I am going > to push back hard on having SSO be the second major feature we add to > our website (or the third, or even the tenth). > > We'll see where that discussion goes. > I *strongly* like the idea of packaging SSO between Yesod app and Discourse as an independent library we just use because that's in general a great way to deal with generalized stuff like that. But I want SSO implemented ASAP, immediately if possible. The cleanliness and ease of managing everything about our use of Discourse going forward and the site itself will be really nice if we start Discourse with SSO from the get-go. I don't want all sorts of awkward challenges in transition later after we have bunches of disconnected users on each system and then try to push SSO then. > On Mon, Dec 05, 2016 at 04:13:42AM +0200, fr33domlover wrote: >> From: fr33domlover >> >> --- >> website/Snowdrift.cabal | 7 >> website/config/routes| 2 ++ >> website/config/settings.yml | 4 +++ >> website/src/Application.hs | 1 + >> website/src/Discourse.hs | 73 >> >> website/src/Handler/Discourse.hs | 55 ++ >> website/src/Settings.hs | 4 +++ >> 7 files changed, 146 insertions(+) >> create mode 100644 website/src/Discourse.hs >> create mode 100644 website/src/Handler/Discourse.hs >> >> diff --git a/website/Snowdrift.cabal b/website/Snowdrift.cabal >> index 9c1664c..b5cfaa5 100644 >> --- a/website/Snowdrift.cabal >> +++ b/website/Snowdrift.cabal >> @@ -40,6 +40,7 @@ library >> Avatar >> Application >> Css >> +Discourse >> Email >> Foundation >> Import >> @@ -49,6 +50,7 @@ library >> Settings.StaticFiles >> Handler >> Handler.Dashboard >> +Handler.Discourse >> Handler.PaymentInfo >> Handler.Pledge >> Handler.Project >> @@ -74,6 +76,7 @@ library >> , bytestring >= 0.9 && < 0.11 >> , classy-prelude >= 0.10.2 >> , classy-prelude-yesod >= 0.10.2 >> +, cryptonite >> , data-default >> , errors >> , esqueleto >> @@ -82,8 +85,10 @@ library >> , formattable >> , hjsmin >= 0.1 >> , http-client >> +, http-types >> , lens >> , libravatar >> +, memory >> , mime-mail >> , monad-logger >= 0.3 && < 0.4 >> , nonce >> @@ -99,6 +104,7 @@ library >> , text >= 0.11&& < 2.0 >> , time >> , titlecase >> +, transformers >> , unordered-containers >> , wai >> , wai-extra >= 3.0 && < 3.1 >> @@ -122,6 +128,7 @@ library >> RecordWildCards >> ScopedTypeVariables >> TemplateHaskell >> +TupleSections >> TypeFamilies >> ViewPatterns >> >> diff --git a/website/config/routes b/website/config/routes >> index 9e4e079..30fdef8 100644 >> --- a/website/config/routes >> +++ b/website/config/routes >> @@ -26,6 +26,8 @@ >> /p/snowdrift SnowdriftProjectR GET >> /pledge/snowdrift PledgeSnowdriftR POST DELETE >> >> +/discourse/sso DiscourseR GET >> + >> -- ## Backward compatibility routes >> >> -- Prevents breakage of external links to the old wiki. See >> diff --git a/website/config/settings.yml b/website/config/settings.yml >> index 3c30c0f..e4e30bb 100644 >> --- a/website/config/settings.yml >> +++ b/website/config/settings.yml >> @@ -44,3 +44,7 @@ send-email: "_env:SD_EMAILS:false" >> # chreekat for assistance. >> stripe-secret-key: "_env:STRIPE_SECRET_KEY:" >> stripe-publishable-key: "_env:STRIPE_PUBLISHABLE_KEY:" >> + >> +# Discourse SSO >> +discourse-url: "https://discourse.snowdrift.coop"; >> +discourse-sso-secret: "" >> diff --git a/website/src/Application.hs b/website/src/Application.hs >> index 8ccd6b2..761d3f8 100644 >> --- a/website/src/Application.hs >> +++ b/website/src/Application.hs >> @@ -35,6 +35,7 @@ import qualified Yesod.GitRev as G >> >> import Handler >> import Handler.Dashboard >> +import Handler.Discourse >> import Handler.PaymentInfo >> import Handler.Pledge >> import Handler.Project >> diff --git a/website/src/Discourse.hs b/website/src/Discourse.hs >> new file mode 100644 >> index 000..cca0bb1 >> --- /dev/null >> +++ b/website/src/Discourse.hs >> @@ -0,0 +1,73 @@ >> +module Discourse where >> + >> +import Prelude >> + >> +import Crypto.Hash.Algorithms (SHA256) >> +import Crypto.MAC.HMAC >> +import Data.ByteArray.Encoding >> +import Data.ByteString (ByteStri
Re: [Snowdrift-dev] [PATCH] Discourse SSO support
On 12/05/2016 11:34 AM, Bryan Richter wrote: > Thanks for this. I think the best way to make use of this is to package > up the logic specific to handling SSO requests in an independent > library, so we can use it later. > > That's not about you, or about this code. :) It's just that I am going > to push back hard on having SSO be the second major feature we add to > our website (or the third, or even the tenth). > > We'll see where that discussion goes. > I *strongly* like the idea of packaging SSO between Yesod app and Discourse as an independent library we just use because that's in general a great way to deal with generalized stuff like that. But I want SSO implemented ASAP, immediately if possible. The cleanliness and ease of managing everything about our use of Discourse going forward and the site itself will be really nice if we start Discourse with SSO from the get-go. I don't want all sorts of awkward challenges in transition later after we have bunches of disconnected users on each system and then try to push SSO then. > On Mon, Dec 05, 2016 at 04:13:42AM +0200, fr33domlover wrote: >> From: fr33domlover >> >> --- >> website/Snowdrift.cabal | 7 >> website/config/routes| 2 ++ >> website/config/settings.yml | 4 +++ >> website/src/Application.hs | 1 + >> website/src/Discourse.hs | 73 >> >> website/src/Handler/Discourse.hs | 55 ++ >> website/src/Settings.hs | 4 +++ >> 7 files changed, 146 insertions(+) >> create mode 100644 website/src/Discourse.hs >> create mode 100644 website/src/Handler/Discourse.hs >> >> diff --git a/website/Snowdrift.cabal b/website/Snowdrift.cabal >> index 9c1664c..b5cfaa5 100644 >> --- a/website/Snowdrift.cabal >> +++ b/website/Snowdrift.cabal >> @@ -40,6 +40,7 @@ library >> Avatar >> Application >> Css >> +Discourse >> Email >> Foundation >> Import >> @@ -49,6 +50,7 @@ library >> Settings.StaticFiles >> Handler >> Handler.Dashboard >> +Handler.Discourse >> Handler.PaymentInfo >> Handler.Pledge >> Handler.Project >> @@ -74,6 +76,7 @@ library >> , bytestring >= 0.9 && < 0.11 >> , classy-prelude >= 0.10.2 >> , classy-prelude-yesod >= 0.10.2 >> +, cryptonite >> , data-default >> , errors >> , esqueleto >> @@ -82,8 +85,10 @@ library >> , formattable >> , hjsmin >= 0.1 >> , http-client >> +, http-types >> , lens >> , libravatar >> +, memory >> , mime-mail >> , monad-logger >= 0.3 && < 0.4 >> , nonce >> @@ -99,6 +104,7 @@ library >> , text >= 0.11&& < 2.0 >> , time >> , titlecase >> +, transformers >> , unordered-containers >> , wai >> , wai-extra >= 3.0 && < 3.1 >> @@ -122,6 +128,7 @@ library >> RecordWildCards >> ScopedTypeVariables >> TemplateHaskell >> +TupleSections >> TypeFamilies >> ViewPatterns >> >> diff --git a/website/config/routes b/website/config/routes >> index 9e4e079..30fdef8 100644 >> --- a/website/config/routes >> +++ b/website/config/routes >> @@ -26,6 +26,8 @@ >> /p/snowdrift SnowdriftProjectR GET >> /pledge/snowdrift PledgeSnowdriftR POST DELETE >> >> +/discourse/sso DiscourseR GET >> + >> -- ## Backward compatibility routes >> >> -- Prevents breakage of external links to the old wiki. See >> diff --git a/website/config/settings.yml b/website/config/settings.yml >> index 3c30c0f..e4e30bb 100644 >> --- a/website/config/settings.yml >> +++ b/website/config/settings.yml >> @@ -44,3 +44,7 @@ send-email: "_env:SD_EMAILS:false" >> # chreekat for assistance. >> stripe-secret-key: "_env:STRIPE_SECRET_KEY:" >> stripe-publishable-key: "_env:STRIPE_PUBLISHABLE_KEY:" >> + >> +# Discourse SSO >> +discourse-url: "https://discourse.snowdrift.coop"; >> +discourse-sso-secret: "" >> diff --git a/website/src/Application.hs b/website/src/Application.hs >> index 8ccd6b2..761d3f8 100644 >> --- a/website/src/Application.hs >> +++ b/website/src/Application.hs >> @@ -35,6 +35,7 @@ import qualified Yesod.GitRev as G >> >> import Handler >> import Handler.Dashboard >> +import Handler.Discourse >> import Handler.PaymentInfo >> import Handler.Pledge >> import Handler.Project >> diff --git a/website/src/Discourse.hs b/website/src/Discourse.hs >> new file mode 100644 >> index 000..cca0bb1 >> --- /dev/null >> +++ b/website/src/Discourse.hs >> @@ -0,0 +1,73 @@ >> +module Discourse where >> + >> +import Prelude >> + >> +import Crypto.Hash.Algorithms (SHA256) >> +import Crypto.MAC.HMAC >> +import Data.ByteArray.Encoding >> +import Data.ByteString (ByteStri
[Snowdrift-dev] [PATCH] Discourse SSO support
From: fr33domlover --- website/Snowdrift.cabal | 8 website/config/routes| 2 + website/config/settings.yml | 3 ++ website/src/Application.hs | 1 + website/src/Discourse.hs | 86 website/src/Handler/Discourse.hs | 49 +++ website/src/Settings.hs | 2 + 7 files changed, 151 insertions(+) create mode 100644 website/src/Discourse.hs create mode 100644 website/src/Handler/Discourse.hs diff --git a/website/Snowdrift.cabal b/website/Snowdrift.cabal index 9c1664c..8eca05d 100644 --- a/website/Snowdrift.cabal +++ b/website/Snowdrift.cabal @@ -40,6 +40,7 @@ library Avatar Application Css +Discourse Email Foundation Import @@ -49,6 +50,7 @@ library Settings.StaticFiles Handler Handler.Dashboard +Handler.Discourse Handler.PaymentInfo Handler.Pledge Handler.Project @@ -70,10 +72,12 @@ library , crowdmatch -- Other , aeson >= 0.6 && < 0.12 +, base64-bytestring , blaze-html , bytestring >= 0.9 && < 0.11 , classy-prelude >= 0.10.2 , classy-prelude-yesod >= 0.10.2 +, cryptonite , data-default , errors , esqueleto @@ -82,8 +86,10 @@ library , formattable , hjsmin >= 0.1 , http-client +, http-types , lens , libravatar +, memory , mime-mail , monad-logger >= 0.3 && < 0.4 , nonce @@ -99,6 +105,7 @@ library , text >= 0.11&& < 2.0 , time , titlecase +, transformers , unordered-containers , wai , wai-extra >= 3.0 && < 3.1 @@ -122,6 +129,7 @@ library RecordWildCards ScopedTypeVariables TemplateHaskell +TupleSections TypeFamilies ViewPatterns diff --git a/website/config/routes b/website/config/routes index 9e4e079..30fdef8 100644 --- a/website/config/routes +++ b/website/config/routes @@ -26,6 +26,8 @@ /p/snowdrift SnowdriftProjectR GET /pledge/snowdrift PledgeSnowdriftR POST DELETE +/discourse/sso DiscourseR GET + -- ## Backward compatibility routes -- Prevents breakage of external links to the old wiki. See diff --git a/website/config/settings.yml b/website/config/settings.yml index 3c30c0f..61ff751 100644 --- a/website/config/settings.yml +++ b/website/config/settings.yml @@ -44,3 +44,6 @@ send-email: "_env:SD_EMAILS:false" # chreekat for assistance. stripe-secret-key: "_env:STRIPE_SECRET_KEY:" stripe-publishable-key: "_env:STRIPE_PUBLISHABLE_KEY:" + +# Discourse SSO +discourse-sso-secret: "" diff --git a/website/src/Application.hs b/website/src/Application.hs index 8ccd6b2..761d3f8 100644 --- a/website/src/Application.hs +++ b/website/src/Application.hs @@ -35,6 +35,7 @@ import qualified Yesod.GitRev as G import Handler import Handler.Dashboard +import Handler.Discourse import Handler.PaymentInfo import Handler.Pledge import Handler.Project diff --git a/website/src/Discourse.hs b/website/src/Discourse.hs new file mode 100644 index 000..83106bb --- /dev/null +++ b/website/src/Discourse.hs @@ -0,0 +1,86 @@ +module Discourse where + +import Prelude + +import Control.Monad.Trans.Except +import Crypto.Hash.Algorithms (SHA256) +import Crypto.MAC.HMAC +import Data.ByteArray.Encoding +import Data.ByteString (ByteString) +import Data.Maybe (catMaybes) +import Data.Text (Text, pack) +import Data.Text.Encoding (encodeUtf8, decodeUtf8') +import Network.HTTP.Types.URI (renderSimpleQuery, parseSimpleQuery) + +import qualified Data.ByteString as B (drop) +import qualified Data.ByteString.Base64 as B64 (decodeLenient) + +import Model + +-- | Information we send back to Discourse once the user logs in through our +-- UI. +data UserInfo = UserInfo +{ ssoEmail :: Text +, ssoId:: UserId +, ssoUsername :: Maybe Text +, ssoFullName :: Maybe Text +, ssoAvatarUrl :: Maybe Text +, ssoBio :: Maybe Text +} + +-- | Type restricted convenience wrapper that computes our HMAC. +hmacSHA256 :: ByteString -> ByteString -> HMAC SHA256 +hmacSHA256 = hmac + +-- | Given secret known in advance and payload given in the query, compute the +-- HMAC-SHA256, to which Discourse refers as the signature. +generateSig +:: ByteString -- ^ Secret +-> ByteString -- ^ Base64 encoded payload +-> ByteString +generateSig secret payload = +convertToBase Base16 $ hmacGetDigest $ hmacSHA256 secret payload + +-- | This validates the payloads's authenticity (i.e. make sure it's really our +-- trusted local Discourse instance) by using the signature as a proof that it +-- knows the SSO secret. This is done by verifying that the HMAC-SH
Re: [Snowdrift-dev] [PATCH] Discourse SSO support
Hello Bryan, If you look at the code you'll see there are 2 parts. The logic, which is a simple single file, and the handler that uses it. Both are quite trivial, it's hardly worth having them separately. I do think it would be great to have them both as a separate package that offers a Yesod subsite or at least the handler function. I didn't do that because Snowdrift uses its own auth class so if I used YesodAuth we wouldn't be able to use the library. Sure I can add some AuthBackend class stuff in the library, but that just begins to be ugly and not worth it, at least at the beginning. The quickest way to get the code ready was to add it straight to the web app, I already sent a new patch, JazzyEagle and I are debugging it and very soon the code will be ready. After that, we can think about moving the code to a separate package and solving issues like the auth class. I'm not sure *I* will be doing that part, but hey, at least I wrote the SSO implementation itself :-) --fr33 On Mon, 5 Dec 2016 11:34:17 -0800 Bryan Richter wrote: > Thanks for this. I think the best way to make use of this is to package > up the logic specific to handling SSO requests in an independent > library, so we can use it later. > > That's not about you, or about this code. :) It's just that I am going > to push back hard on having SSO be the second major feature we add to > our website (or the third, or even the tenth). > > We'll see where that discussion goes. > > On Mon, Dec 05, 2016 at 04:13:42AM +0200, fr33domlover wrote: > > From: fr33domlover > > > > --- > > website/Snowdrift.cabal | 7 > > website/config/routes| 2 ++ > > website/config/settings.yml | 4 +++ > > website/src/Application.hs | 1 + > > website/src/Discourse.hs | 73 > > website/src/Handler/Discourse.hs | > > 55 ++ website/src/Settings.hs | 4 +++ > > 7 files changed, 146 insertions(+) > > create mode 100644 website/src/Discourse.hs > > create mode 100644 website/src/Handler/Discourse.hs > > > > diff --git a/website/Snowdrift.cabal b/website/Snowdrift.cabal > > index 9c1664c..b5cfaa5 100644 > > --- a/website/Snowdrift.cabal > > +++ b/website/Snowdrift.cabal > > @@ -40,6 +40,7 @@ library > > Avatar > > Application > > Css > > +Discourse > > Email > > Foundation > > Import > > @@ -49,6 +50,7 @@ library > > Settings.StaticFiles > > Handler > > Handler.Dashboard > > +Handler.Discourse > > Handler.PaymentInfo > > Handler.Pledge > > Handler.Project > > @@ -74,6 +76,7 @@ library > > , bytestring >= 0.9 && < 0.11 > > , classy-prelude >= 0.10.2 > > , classy-prelude-yesod >= 0.10.2 > > +, cryptonite > > , data-default > > , errors > > , esqueleto > > @@ -82,8 +85,10 @@ library > > , formattable > > , hjsmin >= 0.1 > > , http-client > > +, http-types > > , lens > > , libravatar > > +, memory > > , mime-mail > > , monad-logger >= 0.3 && < 0.4 > > , nonce > > @@ -99,6 +104,7 @@ library > > , text >= 0.11&& < 2.0 > > , time > > , titlecase > > +, transformers > > , unordered-containers > > , wai > > , wai-extra >= 3.0 && < 3.1 > > @@ -122,6 +128,7 @@ library > > RecordWildCards > > ScopedTypeVariables > > TemplateHaskell > > +TupleSections > > TypeFamilies > > ViewPatterns > > > > diff --git a/website/config/routes b/website/config/routes > > index 9e4e079..30fdef8 100644 > > --- a/website/config/routes > > +++ b/website/config/routes > > @@ -26,6 +26,8 @@ > > /p/snowdrift SnowdriftProjectR GET > > /pledge/snowdrift PledgeSnowdriftR POST DELETE > > > > +/discourse/sso DiscourseR GET > > + > > -- ## Backward compatibility routes > > > > -- Prevents breakage of external links to the old wiki. See > > diff --git a/website/config/settings.yml b/website/config/settings.yml > > index 3c30c0f..e4e30bb 100644 > > --- a/website/config/settings.yml > > +++ b/website/config/settings.yml > > @@ -44,3 +44,7 @@ send-email: "_env:SD_EMAILS:false" > > # chreekat for assistance. > > stripe-secret-key: "_env:STRIPE_SECRET_KEY:" > > stripe-publishable-key: "_env:STRIPE_PUBLISHABLE_KEY:" > > + > > +# Discourse SSO > > +discourse-url: "https://discourse.snowdrift.coop"; > > +discourse-sso-secret: "" > > diff --git a/website/src/Application.hs b/website/src/Application.hs > > index 8ccd6b2..761d3f8 100644 > > --- a/website/src/Application.hs > > +++ b/website/src/Application.hs > > @@ -35,6 +35,7 @@ import qualified Yesod.GitRev as G > > > > import Handler > > imp