Re: [Snowdrift-dev] [PATCH] Discourse SSO support
For those who may not be watching our Github repo, a patch was submitted yesterday on Github to fix the redirect problem. I downloaded the patch to the Discourse SSO branch I've been working with, and Sidney is now able to login properly the first time she clicks on "Log In" from Discourse: She gets redirected to the Snowdrift.coop login, enters her credentials, clicks "Log in", and *ultimately* gets redirected back to Discourse logged in (technically, a bit more in depth than that, but that's ok). There were concerns presented that this broke things previously, which is why it was changed. Based on what we have now, it appears to be working. I'll test a little bit more manually for now, but ultimately, we need some automated tests written to make sure this works. I have not learned how to write unit tests, so if someone else is up for the challenge OR if someone wants to spend time showing me how to do so, I would definitely appreciate the help. If someone can get me a patch for the unit tests, I can bundle up all the various patches into one MR back to git.snowdrift.coop and help Salt get this up and running. Thanks!! - Jason On Tue, Dec 6, 2016 at 2:11 PM, Stephen Michelwrote: > On Tue, Dec 6, 2016 at 12:30 PM, fr33domlover > wrote: > >> So, Bryan, waiting for your input on this. For now, I suppose it's not >> super >> critical, but it definitely will annoy and confuse users once the >> Discourse >> instance starts getting filled with people and messages (or is it >> alreday? I >> didn't check). >> >> -- fr33 >> > > When last I heard, the plan was to completely wipe the current Discourse > instance and start clean with SSO. To that end, I believe the only people > with accounts on Discourse are team members who have been manually invited. > > I'm not the most in the loop, so take this a grain of salt. > > ~Stephen > > > ___ > Dev mailing list > Dev@lists.snowdrift.coop > https://lists.snowdrift.coop/mailman/listinfo/dev > ___ Dev mailing list Dev@lists.snowdrift.coop https://lists.snowdrift.coop/mailman/listinfo/dev
Re: [Snowdrift-dev] [PATCH] Discourse SSO support
Hello, Jason, thanks for the testing and the report! On Tue, 6 Dec 2016 07:37:04 -0600 Jason Harrerwrote: > [...] > > George is already signed up *and* signed in to Snowdrift.coop and goes to > Discourse for the first time. George will still see a button at the top > that says "Log in". In order for George to post as George, he still needs > to click the "Log in" button in Discourse. When he clicks the "Log in" > button, the SSO logic will happen and George will then be logged in without > having to enter any additional username or password information. (yay!) > At this point, I'm looking into trying to figure out if there's a way for > George to simply be logged in to Discourse without ever having to click > "Log in". That would be Discourse's responsibility. Basically, it would be possible if once you load the Discourse instance website in your browser, either it automatically redirects to SSO login (but that's bad because some users just want to read the conversation, not log in), or a piece of Javascript somehow sends a request to Snowdrift asynchronously. Not sure if it can happen without custom modifications to Snowdrift. I don't know much JS, someone with JS experience could perhaps know more. > Sidney is already signed up for Snowdrift.coop, but she is not currently > logged in to Snowdrift.coop. Sidney goes to Discourse and sees the same > screen as George did, with the "Log in" button at the top. Sidney clicks > on "Log in", and the sso logic redirects her to the Snowdrift.coop login > page. She enters her username and password, and clicks the "Log in" button > on the Snowdrift.coop auth page, and she is redirected to... her > Dashboard. When Sidney manually goes back to Discourse, she still has a > "Log in" button on the Discourse page. When she clicks "Log in" *this* time, > the sso logic works. > > The Snowdrift login page should have been redirected back to the sso > handler, which would have then redirect back to Discourse with the > authentication information (assuming we can keep the GET strings > transferred throughout the various redirects). I tried looking at Bryan's > auth code, but apparently my Haskell skillset is not advanced enough to > fully follow along. I'm not sure what to do to make the modification. If > anyone can help with this, I would greatly appreciate it. That's indeed an issue with Bryan's auth code. Yesod has a "final destination" feature which lets you send the user a web page while specifying where to redirect after that, and that sent page's handler can use the info to actually redirect. That feature originally exists for the auth system: If you load a page that requires login, you're redirected to login with the "final destination" being the page from which you came. That way, after login you are redirected back to where you were. Bryan's code, which replaces YesodAuth, doesn't have that part implemented, or it's still buggy. So, Bryan, waiting for your input on this. For now, I suppose it's not super critical, but it definitely will annoy and confuse users once the Discourse instance starts getting filled with people and messages (or is it alreday? I didn't check). -- fr33 > Thanks!! > > - Jason > > On Mon, Dec 5, 2016 at 4:11 PM, wrote: > > > 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 > >
Re: [Snowdrift-dev] [PATCH] Discourse SSO support
I tested this locally (I set up a local instance of Discourse to test with), and it works... to a point. It seemed easier yesterday to explain things in User Story format, so I'm going to attempt the same here. George is already signed up *and* signed in to Snowdrift.coop and goes to Discourse for the first time. George will still see a button at the top that says "Log in". In order for George to post as George, he still needs to click the "Log in" button in Discourse. When he clicks the "Log in" button, the SSO logic will happen and George will then be logged in without having to enter any additional username or password information. (yay!) At this point, I'm looking into trying to figure out if there's a way for George to simply be logged in to Discourse without ever having to click "Log in". Sidney is already signed up for Snowdrift.coop, but she is not currently logged in to Snowdrift.coop. Sidney goes to Discourse and sees the same screen as George did, with the "Log in" button at the top. Sidney clicks on "Log in", and the sso logic redirects her to the Snowdrift.coop login page. She enters her username and password, and clicks the "Log in" button on the Snowdrift.coop auth page, and she is redirected to... her Dashboard. When Sidney manually goes back to Discourse, she still has a "Log in" button on the Discourse page. When she clicks "Log in" *this* time, the sso logic works. The Snowdrift login page should have been redirected back to the sso handler, which would have then redirect back to Discourse with the authentication information (assuming we can keep the GET strings transferred throughout the various redirects). I tried looking at Bryan's auth code, but apparently my Haskell skillset is not advanced enough to fully follow along. I'm not sure what to do to make the modification. If anyone can help with this, I would greatly appreciate it. Thanks!! - Jason On Mon, Dec 5, 2016 at 4:11 PM,wrote: > 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:
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 Richterwrote: > 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
[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
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 >>
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 >>
[Snowdrift-dev] [PATCH] Discourse SSO support
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 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-SHA256 of the +-- secret and the payload is identical to the signature. +validateSig +:: ByteString -- ^ SSO secret, same one you specify in Discourse settings +-> ByteString -- ^