mirror of
https://github.com/discourse/discourse.git
synced 2024-11-28 02:23:45 +08:00
2 lines
30 KiB
JavaScript
2 lines
30 KiB
JavaScript
export default {"/search": {"posts":[{"id":61693,"name":"Manoel Lemos","username":"mlemos","avatar_template":"/letter_avatar/mlemos/{size}/2.png","uploaded_avatar_id":null,"created_at":"2014-07-15T21:53:56.337-04:00","cooked":"<p>Gents, I'm using an very interesting tool to drive traffic across the different destinations of my community. One destination is the discussion forum running Discourse and other is the blog running WordPress.</p>\n\n<p>This tool is called <a href=\"http://www.hellobar.com\" rel=\"nofollow\">Hello Bar</a> and it is basically a bar that stays in the top of the site and links to other places or can be used to collect emails or social networks followers. It worked fine when I added the bar to my Wordpress Blog, but it failed (a bit) when added to my Discourse forum.</p>\n\n<p>You can check the two situations here:</p>\n\n<ul>\n<li>Blog Ok : <a href=\"http://blog.fazedores.com\" rel=\"nofollow\">http://blog.fazedores.com</a>\n</li>\n<li>Forum Fail : <a href=\"http://forum.fazedores.com\" rel=\"nofollow\">http://forum.fazedores.com</a>\n</li>\n</ul>\n\n<p>The error is that the Discourse page was suposed to be pushed down by the Hello Bar, but it isn't being fully pushed down. Then the layout is broken.</p>\n\n<p>Can anyone help me with this? </p>","post_number":1,"post_type":1,"updated_at":"2014-07-15T21:53:56.337-04:00","reply_count":0,"reply_to_post_number":null,"quote_count":0,"avg_time":30,"incoming_link_count":2,"reads":40,"score":19.5,"yours":false,"topic_slug":null,"topic_id":17638,"display_username":"Manoel Lemos","primary_group_name":null,"version":2,"can_edit":false,"can_delete":false,"can_recover":false,"user_title":null,"actions_summary":[{"id":2,"count":0,"hidden":false,"can_act":null},{"id":3,"count":0,"hidden":false,"can_act":null},{"id":4,"count":0,"hidden":false,"can_act":null},{"id":5,"count":0,"hidden":true,"can_act":null},{"id":6,"count":0,"hidden":false,"can_act":null},{"id":7,"count":0,"hidden":false,"can_act":null},{"id":8,"count":0,"hidden":false,"can_act":null}],"moderator":false,"admin":false,"staff":false,"user_id":7595,"hidden":false,"hidden_reason_id":null,"trust_level":1,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"blurb":"...the discussion forum running Discourse and other is the blog running WordPress. This tool is called <span class='highlighted'>Hello</span> Bar and it is basically a bar that stays in the top of the site and links to other places or can be..."},{"id":56514,"name":"Ova Light","username":"ChrisOva","avatar_template":"/letter_avatar/chrisova/{size}/2.png","uploaded_avatar_id":null,"created_at":"2014-06-13T02:56:00.794-04:00","cooked":"<p>Do you know what are the elements whichI need to modify in the custom CSS editor in order for these parts of the forum to change color ?</p>\n\n<p><div class=\"lightbox-wrapper\"><a href=\"//meta-discourse.r.worldssl.net/uploads/default/31895/338b8068a64b759b.png\" class=\"lightbox\" title=\"00000674.png\"><img src=\"//meta-discourse.r.worldssl.net/uploads/default/_optimized/b35/289/b2338e0876_690x243.png\" width=\"690\" height=\"243\"><div class=\"meta\">\n<span class=\"filename\">00000674.png</span><span class=\"informations\">2644x932 239 KB</span><span class=\"expand\"></span>\n</div></a></div></p>\n\n<p>Is anyone here willing to work for a theme? (50$)</p>\n\n<p>Thanks for reading !</p>","post_number":1,"post_type":1,"updated_at":"2014-06-13T03:05:31.865-04:00","reply_count":0,"reply_to_post_number":null,"quote_count":0,"avg_time":24,"incoming_link_count":1,"reads":31,"score":57.4,"yours":false,"topic_slug":null,"topic_id":16504,"display_username":"Ova Light","primary_group_name":null,"version":5,"can_edit":false,"can_delete":false,"can_recover":false,"user_title":null,"actions_summary":[{"id":2,"count":1,"hidden":false,"can_act":null},{"id":3,"count":0,"hidden":false,"can_act":null},{"id":4,"count":0,"hidden":false,"can_act":null},{"id":5,"count":0,"hidden":true,"can_act":null},{"id":6,"count":0,"hidden":false,"can_act":null},{"id":7,"count":0,"hidden":false,"can_act":null},{"id":8,"count":0,"hidden":false,"can_act":null}],"moderator":false,"admin":false,"staff":false,"user_id":10477,"hidden":false,"hidden_reason_id":null,"trust_level":2,"deleted_at":null,"user_deleted":false,"edit_reason":"downloaded local copies of images","can_view_edit_history":true,"wiki":false,"blurb":"Do you know what are the elements whichI need to modify in the custom CSS editor in order for these parts of the forum to change color ? 00000674.png 00000674.png 2644x932 239 KB Is anyone here wil..."},{"id":40862,"name":"Moe","username":"Moe","avatar_template":"/letter_avatar/moe/{size}/2.png","uploaded_avatar_id":null,"created_at":"2014-02-14T18:35:48.395-05:00","cooked":"<p>Hello,</p>\n\n<p>First and foremost, thanks to the developers of Discourse and everyone who is making great efforts in creating an awesome forum!</p>\n\n<p>I am a Discouse newbie and I am trying to do sso using the CAS sso auth plugin in <a href=\"https://github.com/eriko/cas_sso\" rel=\"nofollow\">https://github.com/eriko/cas_sso</a> .</p>\n\n<p>I am currently making some experiments in authenticating users in Discourse using a test web app I am using as CAS server. I have set up discourse in a VM (vagrant) whereas the CAS server runs in the host machine. I have installed the sso plugin and set the values as indicated (i.e. cas_sso_host, cas_sso_port, etc, as it is a non-standard CAS server), with ssh disabled. </p>\n\n<p>One thing that I noticed is that it seems that there seems to be a cross domain protection acting, the following is a message that appears in the console when I go to login in vagrant discourse:<br></p>\n\n<p></p><pre><code class=\"lang-auto\">Started GET \"/session/csrf\" for 10.0.2.2 at 2014-02-14 17:53:12 -0500\nProcessing by SessionController#csrf as */*\nCompleted 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 0.0ms)</code></pre>\n\n<p>Here 10.0.2.2 is the ip of the CAS server. This server is accessible from vagrant, I tested access to the CAS server URLs using lynx (everything works fine). I should likely mention also that cas_sso_login_url is set to /login and cas_sso_path is set to /cas in the Discourse sso plugin options. I have been also monitoring requests to /cas/login in the CAS server and none of my login attempts from Discourse have made it there. </p>\n\n<p>I am brand new to Discourse and Ruby, so I am having a bit of a struggle here and any insight would be greatly appreciated.</p>\n\n<p>Thank you very much in advance for your time and excellent disposition.</p>\n\n<p>Best regards,<br>Moe</p>","post_number":1,"post_type":1,"updated_at":"2014-02-14T18:35:48.395-05:00","reply_count":0,"reply_to_post_number":null,"quote_count":0,"avg_time":20,"incoming_link_count":60,"reads":57,"score":357.4,"yours":false,"topic_slug":null,"topic_id":12731,"display_username":"Moe","primary_group_name":null,"version":2,"can_edit":false,"can_delete":false,"can_recover":false,"user_title":null,"actions_summary":[{"id":2,"count":1,"hidden":false,"can_act":null},{"id":3,"count":0,"hidden":false,"can_act":null},{"id":4,"count":0,"hidden":false,"can_act":null},{"id":5,"count":0,"hidden":true,"can_act":null},{"id":6,"count":0,"hidden":false,"can_act":null},{"id":7,"count":0,"hidden":false,"can_act":null},{"id":8,"count":0,"hidden":false,"can_act":null}],"moderator":false,"admin":false,"staff":false,"user_id":8596,"hidden":false,"hidden_reason_id":null,"trust_level":1,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"blurb":"<span class='highlighted'>Hello</span>, First and foremost, thanks to the developers of Discourse and everyone who is making great efforts..."},{"id":18691,"name":"Sam Saffron","username":"sam","avatar_template":"/letter_avatar/sam/{size}/2.png","uploaded_avatar_id":null,"created_at":"2013-05-30T21:17:09.213-04:00","cooked":"<p>For the feature I was working on yesterday, <a class=\"mention\" href=\"/users/codinghorror\">@codinghorror</a> wanted a rather complex sentence. </p>\n\n<p></p><blockquote>There is 1 unread and 9 new topics remaining, or browse other topics in [category]</blockquote>\n\n<p>This seemingly simple sentence was a royal nightmare to localize with our existing localization system. Think through all the permutations:</p>\n\n<p>\"There are 2 unread and 9 new topics remaining, or browse other topics in [category]\"<br>\"There are 2 unread and 1 new topic remaining, or browse other topics in [category]\"<br>\"There is 1 unread and 1 new topic remaining, or browse other topics in [category]\" </p>\n\n<p>Trouble with our current system was that you have no sane way of building these kind of sentences, see: <a href=\"http://stackoverflow.com/questions/16825932/clean-pattern-for-localizing-sentences-in-rails-i18n\">http://stackoverflow.com/questions/16825932/clean-pattern-for-localizing-sentences-in-rails-i18n</a> , you can only easily localize one count in a non compound sentence. </p>\n\n<hr><p>To alleviate this I introduce a new mechanism that is available (optionally) client side. The above sentence is localized using: </p>\n\n<p></p><pre><code class=\"text\">There {UNREAD, plural, \n one {is <a href='/unread'>1 unread</a>} \n other {are <a href='/unread'># unread</a>}\n} and {NEW, plural, \n one {<a href='/new'>1 new</a> topic} \n other {<a href='/new'># new</a> topics}} remaining, or browse other topics in {catLink}</code></pre>\n\n<hr><p>The client localization file has a special rule, if a key ends with _MF it is interpreted as a MessageFormat message, then to access it on the client you use:</p>\n\n<p></p><pre><code class=\"javascript\">I18n.messageFormat(\"topic.read_more_in_category_MF\", {\"UNREAD\": unreadTopics, \"NEW\": newTopics, catLink: opts.catLink})</code></pre>\n\n<hr><p>You can see a few other examples here: </p>\n\n<p><aside class=\"onebox githubblob\"><header class=\"source\"><a href=\"https://github.com/discourse/discourse/blob/master/spec/components/js_locale_helper_spec.rb\">\n github.com\n </a>\n </header><article class=\"onebox-body\"><h4><a href=\"https://github.com/discourse/discourse/blob/master/spec/components/js_locale_helper_spec.rb\" target=\"_blank\">discourse/discourse/blob/master/spec/components/js_locale_helper_spec.rb</a></h4>\n<pre><code class=\"\">require 'spec_helper'\nrequire_dependency 'js_locale_helper'\n\ndescribe JsLocaleHelper do\n it 'should be able to generate translations' do\n JsLocaleHelper.output_locale('en').length.should > 0\n end\n\n def setup_message_format(format)\n @ctx = V8::Context.new\n @ctx.eval('MessageFormat = {locale: {}};')\n @ctx.load(Rails.root + 'lib/javascripts/locale/en.js')\n compiled = JsLocaleHelper.compile_message_format('en', format)\n @ctx.eval(\"var test = #{compiled}\")\n end\n\n def localize(opts)\n @ctx.eval(\"test(#{opts.to_json})\")\n end\n\n it 'handles plurals' do</code></pre>\n\n This file has been truncated. <a href=\"https://github.com/discourse/discourse/blob/master/spec/components/js_locale_helper_spec.rb\" target=\"_blank\">show original</a>\n\n\n </article><div style=\"clear: both\"></div>\n</aside></p>\n\n<p>We do not plan at the moment to move to <a href=\"https://github.com/SlexAxton/messageformat.js\">message format</a> style localization everywhere, however it is nice to have this extra bit of flexibility that lets us generate interesting sentences. </p>\n\n<hr><p>On a technical note, this feature adds almost no weight to the client side JavaScript, all message format strings are pre-compiled into a JavaScript function with no external dependencies. The tricks used can be viewed here: <a href=\"https://github.com/discourse/discourse/blob/master/lib/js_locale_helper.rb\">https://github.com/discourse/discourse/blob/master/lib/js_locale_helper.rb</a></p>\n\n<hr><h4>1 minute Message Format primer</h4>\n\n<p></p><pre><code class=\"lang-auto\">f = \"hello\"\nf() => \"hello\"\n\nf = \"hello {WORLD}\"\nf(WORLD: \"world\") => \"hello world\" \nf(WORLD: \"other world\") => \"hello other world\" \n\nf = \"I have {HATS, plural, one {one hat} other {# hats}}\"\nf(HATS: 1) => \"I have one hat\"\nf(HATS: 10) => \"I have 10 hats\" \n\nf = \"I am a {GENDER, select, male {boy}, female {girl}}\"\nf(GENDER: \"male\") => \"I am a boy\"\nf(GENDER: \"female\") => \"I am a girl\"</code></pre>\n\n<hr><p>Our plan for now is to use this strategically, however it is worth noting that this gives more flexibility in localization, for example in <a href=\"http://en.wikipedia.org/wiki/Czech_declension\">czech</a>, the plural form is rather interesting as <a class=\"mention\" href=\"/users/kuba\">@kuba</a> could attest : </p>\n\n<p></p><pre><code class=\"lang-auto\">MessageFormat.locale.cs = function (n) {\n if (n == 1) {\n return 'one';\n }\n if (n == 2 || n == 3 || n == 4) {\n return 'few';\n }\n return 'other';\n};</code></pre>\n\n<p>Message Format supports this fine, built in. </p>\n\n<p></p><pre><code class=\"lang-auto\">f = \"I have {HATS, plural, one {one hat} other {# hats} few {# few hats}}\"</code></pre>","post_number":1,"post_type":1,"updated_at":"2013-05-30T21:31:57.135-04:00","reply_count":1,"reply_to_post_number":null,"quote_count":0,"avg_time":33,"incoming_link_count":44,"reads":68,"score":450.25,"yours":false,"topic_slug":null,"topic_id":7035,"display_username":"Sam Saffron","primary_group_name":"discourse","version":3,"can_edit":false,"can_delete":false,"can_recover":false,"user_title":"co-founder","actions_summary":[{"id":2,"count":6,"hidden":false,"can_act":null},{"id":3,"count":0,"hidden":false,"can_act":null},{"id":4,"count":0,"hidden":false,"can_act":null},{"id":5,"count":0,"hidden":true,"can_act":null},{"id":6,"count":0,"hidden":false,"can_act":null},{"id":7,"count":0,"hidden":false,"can_act":null},{"id":8,"count":0,"hidden":false,"can_act":null}],"moderator":true,"admin":true,"staff":true,"user_id":1,"hidden":false,"hidden_reason_id":null,"trust_level":3,"deleted_at":null,"user_deleted":false,"edit_reason":null,"can_view_edit_history":true,"wiki":false,"blurb":"...hub.com/discourse/discourse/blob/master/lib/js_locale_helper.rb 1 minute Message Format primer f = \"<span class='highlighted'>hello</span>\" f() = > \"<span class='highlighted'>hello</span>\" f = \"<span class='highlighted'>hello</span> {WORLD}\" f(WORLD: \"world\") = > \"<span class='highlighted'>hello</span> world\" f(WORLD: \"other world\") =..."},{"id":41969,"name":"Sam Saffron","username":"sam","avatar_template":"/letter_avatar/sam/{size}/2.png","uploaded_avatar_id":null,"created_at":"2014-02-25T03:30:34.423-05:00","cooked":"<p>Discourse now ships with official hooks to perform auth offsite. </p>\n\n<h3>The Problem</h3>\n\n<p>Many sites wish to integrate with a Discourse site, however want to keep all user registration in a separate site. In such a setup all Login operations should be outsourced to a different site. </p>\n\n<h3>What if I would like SSO in conjunction with existing auth?</h3>\n\n<p>The intention around SSO is to replace Discourse authentication, if you would like to add a new provider see existing plugins such as: <a href=\"https://meta.discourse.org/t/vk-com-login-vkontakte/12987\">https://meta.discourse.org/t/vk-com-login-vkontakte/12987</a></p>\n\n<h3>Enabling SSO</h3>\n\n<p>To enable single sign on you have 3 settings you need to fill out:</p>\n\n<p><div class=\"lightbox-wrapper\"><a href=\"//meta-discourse.global.ssl.fastly.net/uploads/default/3415/c68d5890b0f7bd4f.png\" class=\"lightbox\" title=\"Pasted image\"><img src=\"//meta-discourse.global.ssl.fastly.net/uploads/default/_optimized/07c/3bf/3fa1d69ceb_690x207.png\" width=\"690\" height=\"207\"><div class=\"meta\">\n<span class=\"filename\">Pasted image</span><span class=\"informations\">798x240 16.8 KB</span><span class=\"expand\"></span>\n</div></a></div> </p>\n\n<p><code>enable_sso</code> : must be enabled, global switch<br><code>sso_url</code>: the <strong>offsite</strong> URL users will be sent to when attempting to log on<br><code>sso_secret</code>: a secret string used to hash SSO payloads. Ensures payloads are authentic.</p>\n\n<p>Once <code>enable_sso</code> is set to true:</p>\n\n<ul>\n<li>Clicking on login or avatar will, redirect you to <code>/session/sso</code> which in turn will redirect users to <code>sso_url</code> with a signed payload.</li>\n<li>Users will not be allowed to \"change password\". That field is removed from the user profile.</li>\n<li>Users will no longer be able to use Discourse auth (username/password, google, etc)</li>\n</ul>\n\n<h3>What if you check it by mistake?</h3>\n\n<p>If you check <code>enable_sso</code> by mistake and need to revert to the original state and no longer have access to the admin panel</p>\n\n<p>run:</p>\n\n<p></p><pre><code class=\"lang-auto\">./launcher enter app\nrails c\nirb > SiteSetting.enable_sso = false\nirb > exit\nexit</code></pre>\n\n<h3>Implementing SSO on your site</h3>\n\n<p>Discourse will redirect clients to <code>sso_url</code> with a signed payload: (say sso_url is <code>https://somesite.com/sso</code>)</p>\n\n<p>You will receive incoming traffic with the following</p>\n\n<p><code>https://somesite.com/sso?sso=PAYLOAD&sig=SIG</code></p>\n\n<p>The payload is a Base64 encoded string comprising of a <a href=\"http://en.wikipedia.org/wiki/Nonce\">nonce</a>. The payload is always a valid querystring. </p>\n\n<p>For example, if the nonce is ABCD. raw_payload will be:</p>\n\n<p><code>nonce=ABCD</code>, this raw payload is <a href=\"http://en.wikipedia.org/wiki/Base64\">base 64</a> encoded.</p>\n\n<p>The endpoint being called must</p>\n\n<ol>\n<li>Validate the signature, ensure that HMAC-SHA256 of sso_secret, PAYLOAD is equal to the sig</li>\n<li>Perform whatever authentication it has to</li>\n<li>Create a new payload with <strong>nonce</strong>, <strong>email</strong>, <strong>external_id</strong> and optionally (username, name) </li>\n<li>Base64 encode the payload</li>\n<li>Calculate a HMAC-SHA256 hash of the using sso_secret as the key and Base64 encoded payload as text </li>\n<li>Redirect back to <code>http://discourse_site/session/sso_login?sso=payload&sig=sig</code>\n</li>\n</ol>\n\n<p>Discourse will validate that the nonce is valid (if valid it will expire it right away so it can no longer be used) it will attempt to:</p>\n\n<ol>\n<li>Log the user on by looking up an already associated <strong>external_id</strong> in the SingleSignOnRecord model</li>\n<li>Log the user on by using the email provided (updating external_id)</li>\n<li>Create a new account for the user providing (email, username, name) updating external_id</li>\n</ol>\n\n<h3>Security concerns</h3>\n\n<p>The nonce (one time token) will expire automatically after 10 minutes. This means that as soon as the user is redirected to your site they have 10 minutes to log in / create a new account. </p>\n\n<p>The protocol is safe against replay attacks as nonce may only be used once.</p>\n\n<h3>Reference implementation</h3>\n\n<p>Discourse contains a reference implementation of the SSO class:</p>\n\n<aside class=\"onebox githubblob\">\n <header class=\"source\">\n <a href=\"https://github.com/discourse/discourse/blob/master/lib/single_sign_on.rb\">\n github.com\n </a>\n </header>\n <article class=\"onebox-body\">\n <h4><a href=\"https://github.com/discourse/discourse/blob/master/lib/single_sign_on.rb\" target=\"_blank\">discourse/discourse/blob/master/lib/single_sign_on.rb</a></h4>\n<pre><code class=\"\">class SingleSignOn\n ACCESSORS = [:nonce, :name, :username, :email,\n :about_me, :external_id]\n FIXNUMS = []\n NONCE_EXPIRY_TIME = 10.minutes\n\n attr_accessor(*ACCESSORS)\n attr_accessor :sso_secret, :sso_url\n\n def self.sso_secret\n raise RuntimeError, \"sso_secret not implemented on class, be sure to set it on instance\"\n end\n\n def self.sso_url\n raise RuntimeError, \"sso_url not implemented on class, be sure to set it on instance\"\n end\n\n def self.parse(payload, sso_secret = nil)\n sso = new\n sso.sso_secret = sso_secret if sso_secret\n</code></pre>\n\n This file has been truncated. <a href=\"https://github.com/discourse/discourse/blob/master/lib/single_sign_on.rb\" target=\"_blank\">show original</a>\n\n\n </article>\n <div style=\"clear: both\"></div>\n</aside>\n\n\n<p>A trivial implementation would be:</p>\n\n<p></p><pre><code class=\"lang-auto\">class DiscourseSsoController < ApplicationController\n def sso\n secret = \"MY_SECRET_STRING\"\n sso = SingleSignOn.parse(request.query_string, secret)\n sso.email = \"user@email.com\"\n sso.name = \"Bill Hicks\"\n sso.username = \"bill@hicks.com\"\n sso.external_id = \"123\" # unique to your application\n sso.sso_secret = secret\n\n redirect_to sso.to_url(\"http://l.discourse/session/sso_login\")\n end\nend</code></pre>\n\n<h3>Transitioning to and from single sign on.</h3>\n\n<p>The system always trusts emails provided by the single sign on endpoint. This means that if you had an existing account in the past on Discourse with SSO disabled, SSO will simply re-use it and avoid creating a new account. </p>\n\n<p>If you ever turn off SSO, users will be able to reset passwords and gain access back to their accounts. </p>\n\n<h3>Real world example:</h3>\n\n<p>Given the following settings:</p>\n\n<p>Discourse domain: <code>http://discuss.example.com</code><br>SSO url : <code>http://www.example.com/discourse/sso</code><br>SSO secret: <code>d836444a9e4084d5b224a60c208dce14</code></p>\n\n<p><strong>User attempt to login</strong> </p>\n\n<ul>\n<li><p>Nonce is generated: <code>cb68251eefb5211e58c00ff1395f0c0b</code></p></li>\n<li><p>Raw payload is generated: <code>nonce=cb68251eefb5211e58c00ff1395f0c0b</code></p></li>\n<li><p>Payload is Base64 encoded: <code>bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI=\\n</code></p></li>\n<li><p>Payload is URL encoded: <code>bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D%0A</code></p></li>\n<li><p>HMAC-SHA256 is generated on the encoded payload: <code>2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56</code></p></li>\n</ul>\n\n<p>Finally browser is redirected to:</p>\n\n<p><code>http://www.example.com/discourse/sso?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGI%3D%0A&sig=2828aa29899722b35a2f191d34ef9b3ce695e0e6eeec47deb46d588d70c7cb56</code></p>\n\n<p><strong>On the other end</strong></p>\n\n<ol>\n<li>Payload is <strong>validated</strong> using HMAC-SHA256, if the sig mismatches, process aborts. </li>\n<li>By reversing the steps above nonce is extracted. </li>\n</ol>\n\n<p>User logs in:</p>\n\n<p></p><pre><code class=\"lang-auto\">name: sam\nexternal_id: hello123\nemail: test@test.com\nusername: samsam</code></pre>\n\n<ul><li>Unsigned payload is generated:</li></ul>\n\n<p><code>nonce=cb68251eefb5211e58c00ff1395f0c0b&name=sam&username=samsam&email=test%40test.com&external_id=hello123</code></p>\n\n<p><small>order does not matter, values are URL encoded</small></p>\n\n<ul><li>Payload is Base64 encoded</li></ul>\n\n<p><code>\"bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1z\\nYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRl\\ncm5hbF9pZD1oZWxsbzEyMw==\\n</code></p>\n\n<ul><li>Payload is URL encoded</li></ul>\n\n<p><code>bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1z%0AYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRl%0Acm5hbF9pZD1oZWxsbzEyMw%3D%3D%0A</code></p>\n\n<ul><li>Payload is signed</li></ul>\n\n<p><code>1c884222282f3feacd76802a9dd94e8bc8deba5d619b292bed75d63eb3152c0b</code></p>\n\n<ul><li>Browser redirects to:</li></ul>\n\n<p><code>http://discuss.example.com/session/sso_login?sso=bm9uY2U9Y2I2ODI1MWVlZmI1MjExZTU4YzAwZmYxMzk1ZjBjMGImbmFtZT1z%0AYW0mdXNlcm5hbWU9c2Ftc2FtJmVtYWlsPXRlc3QlNDB0ZXN0LmNvbSZleHRl%0Acm5hbF9pZD1oZWxsbzEyMw%3D%3D%0A&sig=1c884222282f3feacd76802a9dd94e8bc8deba5d619b292bed75d63eb3152c0b</code></p>\n\n<h3>Future work</h3>\n\n<ul>\n<li><p>We would like to gather more reference implementations for SSO on other platforms. If you have one please post to <a href=\"https://meta.discourse.org/category/extensibility/sso\">the Extensibility / SSO category</a>.</p></li>\n<li><p>Add session expiry and/or revalidation logic, so users are not logged in forever. </p></li>\n<li><p>Create an API endpoint to log off users, in case somebody logs off the main site. </p></li>\n<li><p>Consider adding a discourse_sso gem to make it easier to implement in Ruby. </p></li>\n</ul>\n\n<h3>Advanced Features</h3>\n\n<ul><li>You can pass through custom user field now: <a href=\"https://meta.discourse.org/t/custom-user-fields/14956\">https://meta.discourse.org/t/custom-user-fields/14956</a>\n</li></ul>\n\n<h2>Updates:</h2>\n\n<p><strong>2-Feb-2014</strong> </p>\n\n<ul>\n<li>use <a href=\"http://en.wikipedia.org/wiki/Hash-based_message_authentication_code\">HMAC</a>-SHA256 instead of SHA256. This is more secure and cleanly separates key from payload.</li>\n<li>removed return_url, the system will automatically redirect users back to the page they were on after login </li>\n</ul>\n\n<p><strong>4-April-2014</strong></p>\n\n<ul><li>Added example</li></ul>\n\n<p><strong>24-April-2014</strong></p>\n\n<ul><li>Make note of custom user fields.</li></ul>\n\n<p><strong>01-August-2014</strong></p>\n\n<ul><li>Changed Rails console instructions to assume Docker setup</li></ul>","post_number":1,"post_type":1,"updated_at":"2014-08-01T17:44:20.164-04:00","reply_count":5,"reply_to_post_number":null,"quote_count":0,"avg_time":41,"incoming_link_count":2284,"reads":536,"score":12367.25,"yours":false,"topic_slug":null,"topic_id":13045,"display_username":"Sam Saffron","primary_group_name":"discourse","version":12,"can_edit":false,"can_delete":false,"can_recover":false,"user_title":"co-founder","actions_summary":[{"id":2,"count":41,"hidden":false,"can_act":null},{"id":3,"count":0,"hidden":false,"can_act":null},{"id":4,"count":0,"hidden":false,"can_act":null},{"id":5,"count":0,"hidden":true,"can_act":null},{"id":6,"count":0,"hidden":false,"can_act":null},{"id":7,"count":0,"hidden":false,"can_act":null},{"id":8,"count":0,"hidden":false,"can_act":null}],"moderator":true,"admin":true,"staff":true,"user_id":1,"hidden":false,"hidden_reason_id":null,"trust_level":3,"deleted_at":null,"user_deleted":false,"edit_reason":"","can_view_edit_history":true,"wiki":false,"blurb":"...ocess aborts. By reversing the steps above nonce is extracted. User logs in: name: sam external_id: <span class='highlighted'>hello</span>123 email: test@test.com username: samsam Unsigned payload is generated: nonce=cb68251eefb5211e58c00..."}],"topics":[{"id":17638,"title":"Hello Bar integration issues","fancy_title":"Hello Bar integration issues","slug":"hello-bar-integration-issues","posts_count":5,"reply_count":2,"highest_post_number":5,"image_url":null,"created_at":"2014-07-15T21:53:56.226-04:00","last_posted_at":"2014-07-15T22:51:01.719-04:00","bumped":true,"bumped_at":"2014-07-15T22:01:39.716-04:00","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":true,"archived":false,"views":84,"like_count":1,"has_summary":false,"archetype":"regular","last_poster_username":null,"category_id":6,"posters":[]},{"id":16504,"title":"Hello, I have two questions :D","fancy_title":"Hello, I have two questions :D","slug":"hello-i-have-two-questions-d","posts_count":2,"reply_count":0,"highest_post_number":2,"image_url":"/uploads/default/_optimized/b35/289/b2338e0876_690x243.png","created_at":"2014-06-13T02:56:00.695-04:00","last_posted_at":"2014-06-13T06:27:28.903-04:00","bumped":true,"bumped_at":"2014-06-13T06:27:28.903-04:00","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"views":97,"like_count":3,"has_summary":false,"archetype":"regular","last_poster_username":null,"category_id":14,"posters":[]},{"id":12731,"title":"CAS sso auth plugin question","fancy_title":"CAS sso auth plugin question","slug":"cas-sso-auth-plugin-question","posts_count":15,"reply_count":5,"highest_post_number":15,"image_url":null,"created_at":"2014-02-14T18:35:48.242-05:00","last_posted_at":"2014-02-25T20:50:16.306-05:00","bumped":true,"bumped_at":"2014-02-25T20:50:16.306-05:00","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"views":440,"like_count":2,"has_summary":false,"archetype":"regular","last_poster_username":null,"category_id":5,"posters":[]},{"id":7035,"title":"Message Format support for localization","fancy_title":"Message Format support for localization","slug":"message-format-support-for-localization","posts_count":7,"reply_count":5,"highest_post_number":7,"image_url":"http://meta.discourse.org/assets/favicons/github-65cd2c8ba8283c55eca7f9e257fa7604.png","created_at":"2013-05-30T21:17:08.971-04:00","last_posted_at":"2014-09-03T03:11:36.653-04:00","bumped":true,"bumped_at":"2014-09-03T03:11:36.653-04:00","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"views":699,"like_count":10,"has_summary":false,"archetype":"regular","last_poster_username":null,"category_id":2,"posters":[]},{"id":13045,"title":"Official Single-Sign-On for Discourse","fancy_title":"Official Single-Sign-On for Discourse","slug":"official-single-sign-on-for-discourse","posts_count":61,"reply_count":37,"highest_post_number":64,"image_url":"/uploads/default/_optimized/07c/3bf/3fa1d69ceb_690x207.png","created_at":"2014-02-25T03:30:34.321-05:00","last_posted_at":"2014-08-01T17:44:56.523-04:00","bumped":true,"bumped_at":"2014-08-07T13:27:14.684-04:00","unseen":false,"pinned":false,"unpinned":null,"visible":true,"closed":false,"archived":false,"views":13377,"like_count":74,"has_summary":true,"archetype":"regular","last_poster_username":null,"category_id":10,"posters":[]}],"users":[{"id":3836,"username":"HelloWorld","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/helloworld/{size}/2.png"},{"id":6315,"username":"instagra","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/instagra/{size}/2.png"},{"id":1743,"username":"hello_jmk","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/hello_jmk/{size}/2.png"},{"id":9349,"username":"hellocate","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/hellocate/{size}/2.png"},{"id":10596,"username":"hellooperator","uploaded_avatar_id":null,"avatar_template":"/letter_avatar/hellooperator/{size}/2.png"}],"categories":[],"grouped_search_result":{"more_posts":true,"more_users":null,"more_categories":null,"post_ids":[61693,56514,40862,18691,41969],"user_ids":[3836,6315,1743,9349,10596],"category_ids":[]}}};
|