From b45f872c0451863519812cc57985603ca2578019 Mon Sep 17 00:00:00 2001 From: nverba Date: Tue, 26 Feb 2013 04:28:32 +0000 Subject: [PATCH] Added Github authentication option, disabled by default with enable options in settings. --- Gemfile | 1 + Gemfile.lock | 4 ++ .../templates/modal/login.js.handlebars | 3 + .../discourse/views/modal/login_view.js | 8 +++ .../stylesheets/components/buttons.css.scss | 6 ++ .../stylesheets/foundation/variables.scss | 1 + .../users/omniauth_callbacks_controller.rb | 33 ++++++++++ app/controllers/users_controller.rb | 4 ++ app/models/github_user_info.rb | 3 + app/models/site_setting.rb | 4 ++ app/models/user.rb | 1 + config/initializers/omniauth.rb | 4 ++ config/locales/client.en.yml | 3 + config/locales/server.en.yml | 4 ++ .../20130226015336_add_github_user_info.rb | 13 ++++ db/structure.sql | 66 ++++++++++++++++++- docs/SOFTWARE.md | 1 + .../complete.html.erb_spec.rb | 12 ++++ 18 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 app/models/github_user_info.rb create mode 100644 db/migrate/20130226015336_add_github_user_info.rb diff --git a/Gemfile b/Gemfile index 38c95519516..f49be1f494a 100644 --- a/Gemfile +++ b/Gemfile @@ -35,6 +35,7 @@ gem "omniauth-openid" gem "openid-redis-store" gem "omniauth-facebook" gem "omniauth-twitter" +gem "omniauth-github" gem 'oj' gem 'pbkdf2' gem 'pg' diff --git a/Gemfile.lock b/Gemfile.lock index 78575bdcb95..67dbdcf1424 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -279,6 +279,9 @@ GEM rack omniauth-facebook (1.4.1) omniauth-oauth2 (~> 1.1.0) + omniauth-github (1.1.0) + omniauth (~> 1.0) + omniauth-oauth2 (~> 1.1) omniauth-oauth (1.0.1) oauth omniauth (~> 1.0) @@ -489,6 +492,7 @@ DEPENDENCIES oj omniauth omniauth-facebook + omniauth-github omniauth-openid omniauth-twitter openid-redis-store diff --git a/app/assets/javascripts/discourse/templates/modal/login.js.handlebars b/app/assets/javascripts/discourse/templates/modal/login.js.handlebars index b605373bd66..2c0d7cff03e 100644 --- a/app/assets/javascripts/discourse/templates/modal/login.js.handlebars +++ b/app/assets/javascripts/discourse/templates/modal/login.js.handlebars @@ -5,6 +5,9 @@
+ {{#if Discourse.SiteSettings.enable_github_logins}} + + {{/if}}

{{i18n login.or}} diff --git a/app/assets/javascripts/discourse/views/modal/login_view.js b/app/assets/javascripts/discourse/views/modal/login_view.js index da08b01968a..f11712ab3c5 100644 --- a/app/assets/javascripts/discourse/views/modal/login_view.js +++ b/app/assets/javascripts/discourse/views/modal/login_view.js @@ -101,6 +101,14 @@ Discourse.LoginView = Discourse.ModalBodyView.extend({ } }, + githubLogin: function() { + var left, top; + this.set('authenticate', 'github'); + left = this.get('lastX') - 400; + top = this.get('lastY') - 200; + return window.open("/auth/github", "_blank", "menubar=no,status=no,height=400,width=800,left=" + left + ",top=" + top); + }, + authenticationComplete: function(options) { if (options.awaiting_approval) { this.flash(Em.String.i18n('login.awaiting_approval'), 'success'); diff --git a/app/assets/stylesheets/components/buttons.css.scss b/app/assets/stylesheets/components/buttons.css.scss index 80e8756ba7a..74fdda7391c 100755 --- a/app/assets/stylesheets/components/buttons.css.scss +++ b/app/assets/stylesheets/components/buttons.css.scss @@ -162,6 +162,12 @@ content: "Y"; } } + &.github { + background: $github; + &:before { + content: "g"; + } + } } // Button Sizes diff --git a/app/assets/stylesheets/foundation/variables.scss b/app/assets/stylesheets/foundation/variables.scss index 39eea57160c..4407937c81c 100644 --- a/app/assets/stylesheets/foundation/variables.scss +++ b/app/assets/stylesheets/foundation/variables.scss @@ -123,6 +123,7 @@ $google: #5b76f7 !default; $facebook: #3b5998 !default; $twitter: #00bced !default; $yahoo: #810293 !default; +$github: #6d6d6d !default; // Layout dimensions diff --git a/app/controllers/users/omniauth_callbacks_controller.rb b/app/controllers/users/omniauth_callbacks_controller.rb index a719a14ae0d..f876fcdde4a 100644 --- a/app/controllers/users/omniauth_callbacks_controller.rb +++ b/app/controllers/users/omniauth_callbacks_controller.rb @@ -19,6 +19,8 @@ class Users::OmniauthCallbacksController < ApplicationController create_or_sign_on_user_using_twitter(auth_token) when "google", "yahoo" create_or_sign_on_user_using_openid(auth_token) + when "github" + create_or_sign_on_user_using_github(auth_token) end end @@ -169,4 +171,35 @@ class Users::OmniauthCallbacksController < ApplicationController end end + def create_or_sign_on_user_using_github(auth_token) + + data = auth_token[:info] + screen_name = data["nickname"] + github_user_id = auth_token["uid"] + + session[:authentication] = { + github_user_id: github_user_id, + github_screen_name: screen_name + } + + user_info = GithubUserInfo.where(:github_user_id => github_user_id).first + + @data = { + username: screen_name, + auth_provider: "Github" + } + + if user_info + if user_info.user.active + log_on_user(user_info.user) + @data[:authenticated] = true + else + @data[:awaiting_activation] = true + # send another email ? + end + else + @data[:name] = screen_name + end + end + end diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 42fdf3cc73f..dc5156d858e 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -177,6 +177,10 @@ class UsersController < ApplicationController if auth[:facebook].present? and FacebookUserInfo.find_by_facebook_user_id(auth[:facebook][:facebook_user_id]).nil? FacebookUserInfo.create!(auth[:facebook].merge(user_id: user.id)) end + + if auth[:github_user_id] && auth[:github_screen_name] && GithubUserInfo.find_by_github_user_id(auth[:github_user_id]).nil? + GithubUserInfo.create(:user_id => user.id, :screen_name => auth[:github_screen_name], :github_user_id => auth[:github_user_id]) + end end diff --git a/app/models/github_user_info.rb b/app/models/github_user_info.rb new file mode 100644 index 00000000000..7f2b4c56d37 --- /dev/null +++ b/app/models/github_user_info.rb @@ -0,0 +1,3 @@ +class GithubUserInfo < ActiveRecord::Base + belongs_to :user +end \ No newline at end of file diff --git a/app/models/site_setting.rb b/app/models/site_setting.rb index d4090f04f47..0963fc8b99d 100644 --- a/app/models/site_setting.rb +++ b/app/models/site_setting.rb @@ -113,6 +113,10 @@ class SiteSetting < ActiveRecord::Base setting(:facebook_app_id, '') setting(:facebook_app_secret, '') + client_setting(:enable_github_logins, false) + setting(:github_client_id, '') + setting(:github_client_secret, '') + setting(:enforce_global_nicknames, true) setting(:discourse_org_access_key, '') setting(:enable_s3_uploads, false) diff --git a/app/models/user.rb b/app/models/user.rb index 1fab84e9972..6b2bf2ef77a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -21,6 +21,7 @@ class User < ActiveRecord::Base has_many :user_visits has_many :invites has_one :twitter_user_info + has_one :github_user_info belongs_to :approved_by, class_name: 'User' validates_presence_of :username diff --git a/config/initializers/omniauth.rb b/config/initializers/omniauth.rb index 41e4c8d4d42..838006e8a23 100644 --- a/config/initializers/omniauth.rb +++ b/config/initializers/omniauth.rb @@ -27,4 +27,8 @@ Rails.application.config.middleware.use OmniAuth::Builder do SiteSetting.twitter_consumer_key, SiteSetting.twitter_consumer_secret + provider :github, + SiteSetting.github_client_id, + SiteSetting.github_client_secret + end diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 93bf0eb6a4f..4c6c6cba47f 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -248,6 +248,9 @@ en: yahoo: title: "Log In with Yahoo" message: "Authenticating with Yahoo (make sure pop up blockers are not enabled)" + github: + title: "Log In with Github" + message: "Authenticating with Github (make sure pop up blockers are not enabled)" composer: saving_draft_tip: "saving" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 060124f7dc8..4b03f4e59d0 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -310,6 +310,10 @@ en: facebook_app_id: "App id for Facebook authentication, registered at https://developers.facebook.com/apps" facebook_app_secret: "App secret for Facebook authentication, registered at https://developers.facebook.com/apps" + enable_github_logins: "Enable Github authentication, requires github_client_id and github_client_secret" + 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" + allow_import: "Allow import, which can replace ALL site data; leave false unless you plan to do imports" active_user_rate_limit_secs: "How frequently we update the 'last_seen_at' field, in seconds" diff --git a/db/migrate/20130226015336_add_github_user_info.rb b/db/migrate/20130226015336_add_github_user_info.rb new file mode 100644 index 00000000000..4887aa3743e --- /dev/null +++ b/db/migrate/20130226015336_add_github_user_info.rb @@ -0,0 +1,13 @@ +class AddGithubUserInfo < ActiveRecord::Migration + def change + create_table :github_user_infos do |t| + t.integer :user_id, :null => false + t.string :screen_name, :null => false + t.integer :github_user_id, :null => false + t.timestamps + end + + add_index :github_user_infos, [:github_user_id], :unique => true + add_index :github_user_infos, [:user_id], :unique => true + end +end \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index c03f0bed118..fa70f2c1037 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -308,6 +308,39 @@ CREATE SEQUENCE facebook_user_infos_id_seq ALTER SEQUENCE facebook_user_infos_id_seq OWNED BY facebook_user_infos.id; +-- +-- Name: github_user_infos; Type: TABLE; Schema: public; Owner: -; Tablespace: +-- + +CREATE TABLE github_user_infos ( + id integer NOT NULL, + user_id integer NOT NULL, + screen_name character varying(255) NOT NULL, + github_user_id integer NOT NULL, + created_at timestamp without time zone NOT NULL, + updated_at timestamp without time zone NOT NULL +); + + +-- +-- Name: github_user_infos_id_seq; Type: SEQUENCE; Schema: public; Owner: - +-- + +CREATE SEQUENCE github_user_infos_id_seq + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +-- +-- Name: github_user_infos_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: - +-- + +ALTER SEQUENCE github_user_infos_id_seq OWNED BY github_user_infos.id; + + -- -- Name: incoming_links; Type: TABLE; Schema: public; Owner: -; Tablespace: -- @@ -1310,6 +1343,13 @@ ALTER TABLE ONLY email_tokens ALTER COLUMN id SET DEFAULT nextval('email_tokens_ ALTER TABLE ONLY facebook_user_infos ALTER COLUMN id SET DEFAULT nextval('facebook_user_infos_id_seq'::regclass); +-- +-- Name: id; Type: DEFAULT; Schema: public; Owner: - +-- + +ALTER TABLE ONLY github_user_infos ALTER COLUMN id SET DEFAULT nextval('github_user_infos_id_seq'::regclass); + + -- -- Name: id; Type: DEFAULT; Schema: public; Owner: - -- @@ -1560,6 +1600,14 @@ ALTER TABLE ONLY topics ADD CONSTRAINT forum_threads_pkey PRIMARY KEY (id); +-- +-- Name: github_user_infos_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: +-- + +ALTER TABLE ONLY github_user_infos + ADD CONSTRAINT github_user_infos_pkey PRIMARY KEY (id); + + -- -- Name: incoming_links_pkey; Type: CONSTRAINT; Schema: public; Owner: -; Tablespace: -- @@ -1888,6 +1936,20 @@ CREATE UNIQUE INDEX index_forum_thread_users_on_forum_thread_id_and_user_id ON t CREATE INDEX index_forum_threads_on_bumped_at ON topics USING btree (bumped_at DESC); +-- +-- Name: index_github_user_infos_on_github_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE UNIQUE INDEX index_github_user_infos_on_github_user_id ON github_user_infos USING btree (github_user_id); + + +-- +-- Name: index_github_user_infos_on_user_id; Type: INDEX; Schema: public; Owner: -; Tablespace: +-- + +CREATE UNIQUE INDEX index_github_user_infos_on_user_id ON github_user_infos USING btree (user_id); + + -- -- Name: index_invites_on_email_and_invited_by_id; Type: INDEX; Schema: public; Owner: -; Tablespace: -- @@ -2539,4 +2601,6 @@ INSERT INTO schema_migrations (version) VALUES ('20130213021450'); INSERT INTO schema_migrations (version) VALUES ('20130213203300'); -INSERT INTO schema_migrations (version) VALUES ('20130221215017'); \ No newline at end of file +INSERT INTO schema_migrations (version) VALUES ('20130221215017'); + +INSERT INTO schema_migrations (version) VALUES ('20130226015336'); \ No newline at end of file diff --git a/docs/SOFTWARE.md b/docs/SOFTWARE.md index 917883a1d88..a13d104ebac 100644 --- a/docs/SOFTWARE.md +++ b/docs/SOFTWARE.md @@ -27,6 +27,7 @@ The following Ruby Gems are used in Discourse: * [omniauth-openid](https://github.com/intridea/omniauth-openid) * [omniauth-facebook](https://github.com/mkdynamic/omniauth-facebook) * [omniauth-twitter](https://github.com/arunagw/omniauth-twitter) +* [omniauth-github](https://github.com/intridea/omniauth-github) * [has_ip_address](https://rubygems.org/gems/has_ip_address) * [vestal_versions](https://rubygems.org/gems/vestal_versions) * [uglifier](https://rubygems.org/gems/uglifier) diff --git a/spec/views/omniauth_callbacks/complete.html.erb_spec.rb b/spec/views/omniauth_callbacks/complete.html.erb_spec.rb index 5b54f8d9c4e..8f1daf28b31 100644 --- a/spec/views/omniauth_callbacks/complete.html.erb_spec.rb +++ b/spec/views/omniauth_callbacks/complete.html.erb_spec.rb @@ -37,6 +37,18 @@ describe "users/omniauth_callbacks/complete.html.erb" do rendered_data["auth_provider"].should eq("OpenId") rendered_data["awaiting_activation"].should eq(true) end + + it "renders github data " do + assign(:data, {:username =>"username", :auth_provider=>"Github", :awaiting_activation=>true}) + + render + + rendered_data = JSON.parse(rendered.match(/window.opener.Discourse.authenticationComplete\((.*)\)/)[1]) + + rendered_data["username"].should eq("username") + rendered_data["auth_provider"].should eq("Github") + rendered_data["awaiting_activation"].should eq(true) + end end