From fd4d384dc12ef5e80ac83d52a8524fd753270c16 Mon Sep 17 00:00:00 2001 From: Dan Callahan <dan.callahan@gmail.com> Date: Mon, 25 Feb 2013 18:10:16 -0600 Subject: [PATCH 1/5] Add Mozilla Persona Omniauth Gem and initializer --- Gemfile | 1 + Gemfile.lock | 11 +++++++++++ config/initializers/omniauth.rb | 3 +++ 3 files changed, 15 insertions(+) diff --git a/Gemfile b/Gemfile index 514329c0a..99e71f0b5 100644 --- a/Gemfile +++ b/Gemfile @@ -36,6 +36,7 @@ gem "openid-redis-store" gem "omniauth-facebook" gem "omniauth-twitter" gem "omniauth-github" +gem "omniauth-browserid", :git => "git://github.com/callahad/omniauth-browserid.git", :branch => "observer_api" gem 'oj' gem 'pbkdf2' gem 'pg' diff --git a/Gemfile.lock b/Gemfile.lock index a5a628f60..6d9dd2047 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -5,6 +5,16 @@ GIT rack-mini-profiler (0.1.23) rack (>= 1.1.3) +GIT + remote: git://github.com/callahad/omniauth-browserid.git + revision: af62d667626c1622de6fe13b60849c3640765ab1 + branch: observer_api + specs: + omniauth-browserid (0.0.2) + faraday + multi_json + omniauth (~> 1.0) + GIT remote: git://github.com/emberjs/ember-rails.git revision: 57bbe3202725e55a8e4eaccba83d663b26bcf024 @@ -490,6 +500,7 @@ DEPENDENCIES nokogiri oj omniauth + omniauth-browserid! omniauth-facebook omniauth-github omniauth-openid diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 838006e8a..5c393bdc2 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -31,4 +31,7 @@ Rails.application.config.middleware.use OmniAuth::Builder do SiteSetting.github_client_id, SiteSetting.github_client_secret + provider :browser_id, + :name => 'persona' + end From 81c545539e341e47eeb9663f450efd308bb69ed5 Mon Sep 17 00:00:00 2001 From: Dan Callahan <dan.callahan@gmail.com> Date: Thu, 28 Feb 2013 18:32:40 -0600 Subject: [PATCH 2/5] Add (ui-only) Persona button to login modal --- .../discourse/templates/modal/login.js.handlebars | 2 ++ app/assets/stylesheets/components/buttons.css.scss | 6 ++++++ app/assets/stylesheets/foundation/variables.scss | 3 ++- config/locales/client.en.yml | 3 +++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/templates/modal/login.js.handlebars b/app/assets/javascripts/discourse/templates/modal/login.js.handlebars index 638db920d..b98ac1d9f 100644 --- a/app/assets/javascripts/discourse/templates/modal/login.js.handlebars +++ b/app/assets/javascripts/discourse/templates/modal/login.js.handlebars @@ -16,6 +16,8 @@ {{#if Discourse.SiteSettings.enable_github_logins}} <button class="btn btn-social github" title="{{i18n login.github.title}}" {{action "githubLogin" target="view"}}>{{i18n login.github.title}}</button> {{/if}} + <br> + <button class="btn btn-social persona" title="{{i18n login.persona.title}}" {{action "personaLogin" target="view"}}>{{i18n login.persona.title}}</button> </div> <h3 style="text-align:center; margin-bottom:10px;"> {{i18n login.or}} diff --git a/app/assets/stylesheets/components/buttons.css.scss b/app/assets/stylesheets/components/buttons.css.scss index 74fdda739..0f0520945 100755 --- a/app/assets/stylesheets/components/buttons.css.scss +++ b/app/assets/stylesheets/components/buttons.css.scss @@ -168,6 +168,12 @@ content: "g"; } } + &.persona { + background: $persona; + &:before { + content: "]"; + } + } } // Button Sizes diff --git a/app/assets/stylesheets/foundation/variables.scss b/app/assets/stylesheets/foundation/variables.scss index 4407937c8..a6bdf11a9 100644 --- a/app/assets/stylesheets/foundation/variables.scss +++ b/app/assets/stylesheets/foundation/variables.scss @@ -124,6 +124,7 @@ $facebook: #3b5998 !default; $twitter: #00bced !default; $yahoo: #810293 !default; $github: #6d6d6d !default; +$persona: #606060 !default; // Layout dimensions @@ -174,4 +175,4 @@ $heart: #fa6c8d; $attention_bg: #e4f2f8; $attention_fg: #1aaae4; -$header-item-highlight: #ecf8f6; \ No newline at end of file +$header-item-highlight: #ecf8f6; diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index ae45c0087..4bd3c6954 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -251,6 +251,9 @@ en: github: title: "Log In with Github" message: "Authenticating with Github (make sure pop up blockers are not enabled)" + persona: + title: "Log In with Any Email Address (Mozilla Persona)" + message: "Authenticating with Persona (make sure pop up blockers are not enabled)" composer: saving_draft_tip: "saving" From ef8cf2f734a06c814ee2f80f37fc3bd5d9be40d2 Mon Sep 17 00:00:00 2001 From: Dan Callahan <dan.callahan@gmail.com> Date: Fri, 1 Mar 2013 09:23:21 -0600 Subject: [PATCH 3/5] Add basic Persona functionality 1. No session integration yet, so automatic login/logout events are suppressed. 2. Popup blockers must be disabled: submits form to target="_blank" --- .../discourse/views/modal/login_view.js | 4 +++ .../users/omniauth_callbacks_controller.rb | 34 +++++++++++++++++++ app/views/common/_persona_javascript.html.erb | 25 ++++++++++++++ app/views/layouts/application.html.erb | 1 + 4 files changed, 64 insertions(+) create mode 100644 app/views/common/_persona_javascript.html.erb diff --git a/app/assets/javascripts/discourse/views/modal/login_view.js b/app/assets/javascripts/discourse/views/modal/login_view.js index f11712ab3..57b88dca1 100644 --- a/app/assets/javascripts/discourse/views/modal/login_view.js +++ b/app/assets/javascripts/discourse/views/modal/login_view.js @@ -109,6 +109,10 @@ Discourse.LoginView = Discourse.ModalBodyView.extend({ return window.open("/auth/github", "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top); }, + personaLogin: function() { + navigator.id.request(); + }, + authenticationComplete: function(options) { if (options.awaiting_approval) { this.flash(Em.String.i18n('login.awaiting_approval'), 'success'); diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index f876fcdde..50350b36a 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -21,6 +21,8 @@ class Users::OmniauthCallbacksController < ApplicationController create_or_sign_on_user_using_openid(auth_token) when "github" create_or_sign_on_user_using_github(auth_token) + when "persona" + create_or_sign_on_user_using_persona(auth_token) end end @@ -169,6 +171,7 @@ class Users::OmniauthCallbacksController < ApplicationController openid_url: identity_url } end + end def create_or_sign_on_user_using_github(auth_token) @@ -200,6 +203,37 @@ class Users::OmniauthCallbacksController < ApplicationController else @data[:name] = screen_name end + + end + + def create_or_sign_on_user_using_persona(auth_token) + + email = auth_token[:info][:email] + + user = User.find_by_email(email) + + if user + if SiteSetting.must_approve_users? and !user.approved? + @data = {awaiting_approval: true} + else + log_on_user(user) + @data = {authenticated: true} + end + else + @data = { + email: email, + email_valid: true, + name: User.suggest_name(email), + username: User.suggest_username(email), + auth_provider: params[:provider].try(:capitalize) + } + + session[:authentication] = { + email: email, + email_valid: true, + } + end + end end diff --git a/app/views/common/_persona_javascript.html.erb b/app/views/common/_persona_javascript.html.erb new file mode 100644 index 000000000..f6448e28a --- /dev/null +++ b/app/views/common/_persona_javascript.html.erb @@ -0,0 +1,25 @@ +<script src="https://login.persona.org/include.js"></script> +<form id="persona_assertion_form" action="/auth/persona/callback" method="post" target="_blank"> + <input type='hidden' name='assertion'/> +</form> +<script> + (function() { + var readyCalled = false; + navigator.id.watch({ + onlogin: function(assertion) { + if (readyCalled) { + $('#persona_assertion_form input[name=assertion]').val(assertion); + $('#persona_assertion_form').submit(); + } + }, + onlogout: function() { + if (readyCalled) { + Discourse.logout(); + } + }, + onready: function() { + readyCalled = true; + } + }); + }()); +</script> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index e1b44ca5b..a3fd6e0a9 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -58,6 +58,7 @@ <footer id='bottom'></footer> <%= render :partial => "common/discourse_javascript" %> + <%= render :partial => "common/persona_javascript" %> <%= render_google_analytics_code %> <!-- Discourse Version: <%= Discourse::VERSION::STRING %> --> From 23d812a4ab0506d4b588b13abf82ebe192a47fac Mon Sep 17 00:00:00 2001 From: Dan Callahan <dan.callahan@gmail.com> Date: Fri, 1 Mar 2013 13:22:54 -0600 Subject: [PATCH 4/5] Use AJAX for submitting Persona credentials. Fixes issue with needing to unblock popups. --- .../users/omniauth_callbacks_controller.rb | 5 +++++ app/views/common/_persona_javascript.html.erb | 15 ++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index 50350b36a..9a57c58eb 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -24,6 +24,11 @@ class Users::OmniauthCallbacksController < ApplicationController when "persona" create_or_sign_on_user_using_persona(auth_token) end + + respond_to do |format| + format.html + format.json { render :json => @data } + end end def failure diff --git a/app/views/common/_persona_javascript.html.erb b/app/views/common/_persona_javascript.html.erb index f6448e28a..48d654f7a 100644 --- a/app/views/common/_persona_javascript.html.erb +++ b/app/views/common/_persona_javascript.html.erb @@ -1,15 +1,20 @@ <script src="https://login.persona.org/include.js"></script> -<form id="persona_assertion_form" action="/auth/persona/callback" method="post" target="_blank"> - <input type='hidden' name='assertion'/> -</form> <script> (function() { var readyCalled = false; navigator.id.watch({ onlogin: function(assertion) { if (readyCalled) { - $('#persona_assertion_form input[name=assertion]').val(assertion); - $('#persona_assertion_form').submit(); + + $.ajax({ + type: 'POST', + url: '/auth/persona/callback', + data: { 'assertion': assertion }, + success: function(data, textStatus, jqXHR) { + Discourse.authenticationComplete(data); + }, + dataType: 'json' + }); } }, onlogout: function() { From 7c87359e02925e14ec43d04bf6ef570a99e71359 Mon Sep 17 00:00:00 2001 From: Dan Callahan <dan.callahan@gmail.com> Date: Fri, 1 Mar 2013 13:51:00 -0600 Subject: [PATCH 5/5] Make Persona configurable --- .../javascripts/discourse/templates/modal/login.js.handlebars | 2 ++ app/models/site_setting.rb | 2 ++ app/views/layouts/application.html.erb | 2 +- config/locales/server.en.yml | 2 ++ 4 files changed, 7 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/discourse/templates/modal/login.js.handlebars b/app/assets/javascripts/discourse/templates/modal/login.js.handlebars index b98ac1d9f..3546063dc 100644 --- a/app/assets/javascripts/discourse/templates/modal/login.js.handlebars +++ b/app/assets/javascripts/discourse/templates/modal/login.js.handlebars @@ -16,8 +16,10 @@ {{#if Discourse.SiteSettings.enable_github_logins}} <button class="btn btn-social github" title="{{i18n login.github.title}}" {{action "githubLogin" target="view"}}>{{i18n login.github.title}}</button> {{/if}} + {{#if Discourse.SiteSettings.enable_persona_logins}} <br> <button class="btn btn-social persona" title="{{i18n login.persona.title}}" {{action "personaLogin" target="view"}}>{{i18n login.persona.title}}</button> + {{/if}} </div> <h3 style="text-align:center; margin-bottom:10px;"> {{i18n login.or}} diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb index 8eee42695..1cd0067a3 100644 --- a/app/models/site_setting.rb +++ b/app/models/site_setting.rb @@ -124,6 +124,8 @@ class SiteSetting < ActiveRecord::Base setting(:github_client_id, '') setting(:github_client_secret, '') + client_setting(:enable_persona_logins, true) + setting(:enforce_global_nicknames, true) setting(:discourse_org_access_key, '') setting(:enable_s3_uploads, false) diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index a3fd6e0a9..81fdd1c6c 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -58,7 +58,7 @@ <footer id='bottom'></footer> <%= render :partial => "common/discourse_javascript" %> - <%= render :partial => "common/persona_javascript" %> + <%= render :partial => "common/persona_javascript" if SiteSetting.enable_persona_logins %> <%= render_google_analytics_code %> <!-- Discourse Version: <%= Discourse::VERSION::STRING %> --> diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 9c2433324..3fc39816f 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -339,6 +339,8 @@ en: github_client_id: "Client id for Github authentication, registered at https://github.com/settings/applications" github_client_secret: "Client secret for Github authentication, registered at https://github.com/settings/applications" + enable_persona_logins: "Enable email-based authentication with Mozilla Persona" + allow_import: "Allow import, which can replace ALL site data; leave false unless you plan to do data imports" active_user_rate_limit_secs: "How frequently we update the 'last_seen_at' field, in seconds"