diff --git a/Gemfile b/Gemfile
index 045baa36974f5518c3d4e2971722ddb182b52e39..62620778f705a13332b250e1e26fea08b52b6238 100644
--- a/Gemfile
+++ b/Gemfile
@@ -8,6 +8,10 @@ gem "mysql2"
# Auth
gem "devise", "~> 2.1.0"
+gem 'omniauth'
+gem 'omniauth-google-oauth2'
+gem 'omniauth-twitter'
+gem 'omniauth-github'
# GITLAB patched libs
gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837"
diff --git a/Gemfile.lock b/Gemfile.lock
index 656bede47661b5de65bf9b2abec5c57880f17913..512e5607adf3b9282bcc87989b37e76d30c37b9a 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -166,6 +166,8 @@ GEM
eventmachine (0.12.10)
execjs (1.4.0)
multi_json (~> 1.0)
+ faraday (0.8.1)
+ multipart-post (~> 1.1)
ffaker (1.14.0)
ffi (1.0.11)
foreman (0.47.0)
@@ -193,6 +195,7 @@ GEM
httparty (0.8.3)
multi_json (~> 1.0)
multi_xml
+ httpauth (0.1)
i18n (0.6.0)
journey (1.0.4)
jquery-rails (2.0.2)
@@ -202,6 +205,8 @@ GEM
jquery-rails
railties (>= 3.1.0)
json (1.7.4)
+ jwt (0.1.5)
+ multi_json (>= 1.0)
kaminari (0.13.0)
actionpack (>= 3.0.0)
activesupport (>= 3.0.0)
@@ -224,12 +229,35 @@ GEM
sprockets (~> 2.0)
multi_json (1.3.6)
multi_xml (0.5.1)
+ multipart-post (1.1.5)
mysql2 (0.3.11)
net-ldap (0.2.2)
nokogiri (1.5.3)
+ oauth (0.4.6)
+ oauth2 (0.8.0)
+ faraday (~> 0.8)
+ httpauth (~> 0.1)
+ jwt (~> 0.1.4)
+ multi_json (~> 1.0)
+ rack (~> 1.2)
omniauth (1.1.0)
hashie (~> 1.2)
rack
+ omniauth-github (1.0.1)
+ omniauth (~> 1.0)
+ omniauth-oauth2 (~> 1.0)
+ omniauth-google-oauth2 (0.1.13)
+ omniauth (~> 1.0)
+ omniauth-oauth2
+ omniauth-oauth (1.0.1)
+ oauth
+ omniauth (~> 1.0)
+ omniauth-oauth2 (1.1.0)
+ oauth2 (~> 0.8.0)
+ omniauth (~> 1.0)
+ omniauth-twitter (0.0.12)
+ multi_json (~> 1.3)
+ omniauth-oauth (~> 1.0)
orm_adapter (0.3.0)
polyglot (0.3.3)
posix-spawn (0.3.6)
@@ -407,7 +435,11 @@ DEPENDENCIES
linguist (~> 1.0.0)!
modernizr (= 2.5.3)
mysql2
+ omniauth
+ omniauth-github
+ omniauth-google-oauth2
omniauth-ldap!
+ omniauth-twitter
pry
pygments.rb!
rack-mini-profiler
diff --git a/app/assets/stylesheets/auth_methods.scss b/app/assets/stylesheets/auth_methods.scss
new file mode 100644
index 0000000000000000000000000000000000000000..ed6f5b0fe2dc9dc72303898980d380cd3903151f
--- /dev/null
+++ b/app/assets/stylesheets/auth_methods.scss
@@ -0,0 +1,10 @@
+.auth_methods {
+ &ul {
+ margin: 0;
+ text-align:center;
+ padding: 5px;
+ &li {
+ display: inline;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss
index ad8be0bc58d6bd2bead88ace9bba0116b63f7332..cc9bd766e2888c393d6f1ccf37eb5a23a8dca21f 100644
--- a/app/assets/stylesheets/main.scss
+++ b/app/assets/stylesheets/main.scss
@@ -124,7 +124,7 @@ $hover: #FDF5D9;
* TODO: clean it
*/
@import "common.scss";
-
+@import "auth_methods.scss";
/**
* Styles related to specific part of app
diff --git a/app/controllers/omniauth_callbacks_controller.rb b/app/controllers/omniauth_callbacks_controller.rb
index d472936b4b40c093e199f4df4bf82ead5f8f59de..3be285ba1f6402f442beaeff09cc3420ad67ec80 100644
--- a/app/controllers/omniauth_callbacks_controller.rb
+++ b/app/controllers/omniauth_callbacks_controller.rb
@@ -9,7 +9,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
error ||= env["omniauth.error.type"].to_s
error.to_s.humanize if error
end
-
+
def ldap
# We only find ourselves here if the authentication to LDAP was successful.
@user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user)
@@ -19,4 +19,33 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
sign_in_and_redirect @user
end
+ Settings.omniauth_providers.each do |provider|
+ define_method provider['name'] do
+ handle_omniauth
+ end
+ end
+
+ private
+
+ def handle_omniauth
+ oauth = request.env['omniauth.auth']
+ provider, uid = oauth['provider'], oauth['uid']
+
+ if current_user
+ # Change a logged-in user's authentication method:
+ current_user.extern_uid = uid
+ current_user.provider = provider
+ current_user.save
+ redirect_to profile_path
+ else
+ @user = User.find_or_new_for_omniauth(oauth)
+
+ if @user
+ sign_in_and_redirect @user
+ else
+ flash[:notice] = "There's no such user!"
+ redirect_to new_user_session_path
+ end
+ end
+ end
end
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 38191f5557116febfc252ebc496974163d8d4369..3c533f5022878e60cb541972870aca450b14e633 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -78,16 +78,16 @@ module ApplicationHelper
end
def show_last_push_widget?(event)
- event &&
+ event &&
event.last_push_to_non_root? &&
!event.rm_ref? &&
- event.project &&
+ event.project &&
event.project.merge_requests_enabled
end
def tab_class(tab_key)
active = case tab_key
-
+
# Project Area
when :wall; wall_tab?
when :wiki; controller.controller_name == "wikis"
@@ -126,4 +126,9 @@ module ApplicationHelper
def hexdigest(string)
Digest::SHA1.hexdigest string
end
+
+ def authbutton(provider, size = 64)
+ image_tag("authbuttons/#{provider.to_s.split('_').first}_#{size}.png",
+ alt: "Sign in with #{provider.to_s.titleize}" )
+ end
end
diff --git a/app/models/user.rb b/app/models/user.rb
index ad6af6a6dd0cf524ec65d2460402b90a18edc5af..fa5d68348498a42112795890df3acd083f79bd85 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -86,10 +86,50 @@ class User < ActiveRecord::Base
where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
end
+ def self.create_from_omniauth(auth, ldap = false)
+ provider, uid = auth.provider, auth.uid
+ name = auth.info.name.force_encoding("utf-8")
+ email = auth.info.email.downcase unless auth.info.email.nil?
+
+ ldap_prefix = ldap ? '(LDAP) ' : ''
+ raise OmniAuth::Error, "#{ldap_prefix}#{provider} does not provide an email"\
+ " address" if auth.info.email.blank?
+
+ logger.info "#{ldap_prefix}Creating user from #{provider} login"\
+ " {uid => #{uid}, name => #{name}, email => #{email}}"
+ password = Devise.friendly_token[0, 8].downcase
+ @user = User.new(
+ extern_uid: uid,
+ provider: provider,
+ name: name,
+ email: email,
+ password: password,
+ password_confirmation: password,
+ projects_limit: Gitlab.config.default_projects_limit,
+ )
+ if Gitlab.config.omniauth.block_auto_created_users && !ldap
+ @user.blocked = true
+ end
+ @user.save!
+ @user
+ end
+
+ def self.find_or_new_for_omniauth(auth)
+ provider, uid = auth.provider, auth.uid
+
+ if @user = User.find_by_provider_and_extern_uid(provider, uid)
+ @user
+ else
+ if Gitlab.config.omniauth.allow_single_sign_on
+ @user = User.create_from_omniauth(auth)
+ @user
+ end
+ end
+ end
+
def self.find_for_ldap_auth(auth, signed_in_resource=nil)
uid = auth.info.uid
provider = auth.provider
- name = auth.info.name.force_encoding("utf-8")
email = auth.info.email.downcase unless auth.info.email.nil?
raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil?
@@ -101,17 +141,7 @@ class User < ActiveRecord::Base
@user.update_attributes(:extern_uid => uid, :provider => provider)
@user
else
- logger.info "Creating user from LDAP login {uid => #{uid}, name => #{name}, email => #{email}}"
- password = Devise.friendly_token[0, 8].downcase
- @user = User.create(
- :extern_uid => uid,
- :provider => provider,
- :name => name,
- :email => email,
- :password => password,
- :password_confirmation => password,
- :projects_limit => Gitlab.config.default_projects_limit
- )
+ create_from_omniauth(auth)
end
end
@@ -148,4 +178,3 @@ end
# bio :string(255)
# blocked :boolean(1) default(FALSE), not null
#
-
diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb
index a03838669cf9c8c859f9d92d10247910fb0c84c0..6b334b873356035ea99c7fe620d1417fc2353d8e 100644
--- a/app/views/devise/sessions/new.html.erb
+++ b/app/views/devise/sessions/new.html.erb
@@ -14,10 +14,15 @@
<%= render :partial => "devise/shared/links" %>
<%- if devise_mapping.omniauthable? %>
- <%- resource_class.omniauth_providers.each do |provider| %>
-
- <%= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), :class => "btn primary" %>
- <% end -%>
+
+
+
+ <%- resource_class.omniauth_providers.each do |provider| %>
+ - <%= link_to authbutton(provider),
+ omniauth_authorize_path(resource_name, provider) %>
+ <% end -%>
+
+
<% end -%>
<% end %>
diff --git a/app/views/layouts/profile.html.haml b/app/views/layouts/profile.html.haml
index b624415dfe119934dbc618a7a664c7a70a55bd90..810b346f1cdf5fa548e30648af891a1de862d8e4 100644
--- a/app/views/layouts/profile.html.haml
+++ b/app/views/layouts/profile.html.haml
@@ -10,7 +10,7 @@
= link_to "Profile", profile_path
%li{class: tab_class(:password)}
- = link_to "Password", profile_password_path
+ = link_to "Authentication", profile_password_path
%li{class: tab_class(:ssh_keys)}
= link_to keys_path do
diff --git a/app/views/profile/password.html.haml b/app/views/profile/password.html.haml
index 257dacb1ad37b90787ad6d09f9e5455b825678f2..1d4d468c38b0dff141e273d5369685e39a289bc3 100644
--- a/app/views/profile/password.html.haml
+++ b/app/views/profile/password.html.haml
@@ -1,19 +1,31 @@
%h3.page_title Password
%hr
+
= form_for @user, url: profile_password_path, method: :put do |f|
- .data
- %p.slead After successful password update you will be redirected to login page where you should login with new password
- -if @user.errors.any?
- .alert-message.block-message.error
- %ul
- - @user.errors.full_messages.each do |msg|
- %li= msg
+ .row
+ .span7
+ .data
+ %p.slead After successful password update you will be redirected to login page where you should login with new password
+ -if @user.errors.any?
+ .alert-message.block-message.error
+ %ul
+ - @user.errors.full_messages.each do |msg|
+ %li= msg
+
+ .clearfix
+ = f.label :password
+ .input= f.password_field :password
+ .clearfix
+ = f.label :password_confirmation
+ .input= f.password_field :password_confirmation
- .clearfix
- = f.label :password
- .input= f.password_field :password
- .clearfix
- = f.label :password_confirmation
- .input= f.password_field :password_confirmation
+ - if Settings.omniauth.enabled
+ .span5.right
+ .auth_methods.alert.alert-info
+ %strong Tip: Use one of the following sites to login
+ %ul
+ - User.omniauth_providers.each do |provider|
+ %li= link_to authbutton(provider), |
+ omniauth_authorize_path(User, provider) |
.actions
= f.submit 'Save', class: "btn primary"
diff --git a/app/views/profile/show.html.haml b/app/views/profile/show.html.haml
index 95cce2bb6b6c4642b9388f4c8934aa0dca3af694..4d89cd3dcb3332c509b0fe613e1605abc4a98f4c 100644
--- a/app/views/profile/show.html.haml
+++ b/app/views/profile/show.html.haml
@@ -49,6 +49,13 @@
%strong Tip:
You can change your avatar at gravatar.com
+ - if Settings.omniauth.enabled && @user.provider?
+ %h4
+ Omniauth Providers:
+ = link_to "Change", profile_password_path, class: "btn small right"
+ You can login through #{@user.provider.titleize}!
+ = authbutton(@user.provider, 32)
+
%h4
Personal projects:
%small.right
diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example
index be36ee6da0dfdc8d4fdfadfd0a857ce14892ba62..b5aae4971ed80466d751fac0e608cf98fe494495 100644
--- a/config/gitlab.yml.example
+++ b/config/gitlab.yml.example
@@ -48,3 +48,21 @@ git:
git_max_size: 5242880 # 5.megabytes
# Git timeout to read commit, in seconds
git_timeout: 10
+
+# Omniauth configuration
+omniauth:
+ enabled: false
+ providers:
+ allow_single_sign_on: false
+ block_auto_created_users: true
+
+# omniauth:
+# enabled: true
+# providers:
+# - { name: 'google_oauth2', app_id: 'YOUR APP ID',
+# app_secret: 'YOUR APP SECRET',
+# args: { access_type: 'offline', approval_prompt: '' } }
+# - { name: 'twitter', app_id: 'YOUR APP ID',
+# app_secret: 'YOUR APP SECRET'}
+# - { name: 'github', app_id: 'YOUR APP ID',
+# app_secret: 'YOUR APP SECRET' }
diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb
index 8165d6c2eeaf258ef6bc13a6e3cc0ac0933bff04..13e12ff2acee95757331563c3f784ec9eb040b1c 100644
--- a/config/initializers/1_settings.rb
+++ b/config/initializers/1_settings.rb
@@ -6,7 +6,7 @@ class Settings < Settingslogic
self.web['protocol'] ||= web.https ? "https" : "http"
end
- def web_host
+ def web_host
self.web['host'] ||= 'localhost'
end
@@ -14,11 +14,11 @@ class Settings < Settingslogic
self.email['from'] ||= ("notify@" + web_host)
end
- def url
+ def url
self['url'] ||= build_url
- end
+ end
- def web_port
+ def web_port
if web.https
web['port'] = 443
else
@@ -36,7 +36,7 @@ class Settings < Settingslogic
raw_url << web_host
if web_custom_port?
- raw_url << ":#{web_port}"
+ raw_url << ":#{web_port}"
end
raw_url
@@ -112,6 +112,14 @@ class Settings < Settingslogic
app['backup_keep_time'] || 0
end
+ def omniauth_enabled?
+ omniauth['enabled'] || false
+ end
+
+ def omniauth_providers
+ omniauth['providers'] || []
+ end
+
def disable_gravatar?
app['disable_gravatar'] || false
end
diff --git a/db/schema.rb b/db/schema.rb
index 46461e44aad59d13087ad2fcd9a62075e3e56d01..ad4b04167820e42a925f49b1528101284a07ddf3 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
-ActiveRecord::Schema.define(:version => 20120729131232) do
+ActiveRecord::Schema.define(:version => 20120803152018) do
create_table "events", :force => true do |t|
t.string "target_type"
@@ -146,30 +146,30 @@ ActiveRecord::Schema.define(:version => 20120729131232) do
end
create_table "users", :force => true do |t|
- t.string "email", :default => "", :null => false
- t.string "encrypted_password", :limit => 128, :default => "", :null => false
+ t.string "email", :default => "", :null => false
+ t.string "encrypted_password", :default => "", :null => false
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.datetime "remember_created_at"
- t.integer "sign_in_count", :default => 0
+ t.integer "sign_in_count", :default => 0
t.datetime "current_sign_in_at"
t.datetime "last_sign_in_at"
t.string "current_sign_in_ip"
t.string "last_sign_in_ip"
- t.datetime "created_at", :null => false
- t.datetime "updated_at", :null => false
+ t.datetime "created_at", :null => false
+ t.datetime "updated_at", :null => false
t.string "name"
- t.boolean "admin", :default => false, :null => false
- t.integer "projects_limit", :default => 10
- t.string "skype", :default => "", :null => false
- t.string "linkedin", :default => "", :null => false
- t.string "twitter", :default => "", :null => false
+ t.boolean "admin", :default => false, :null => false
+ t.integer "projects_limit", :default => 10
+ t.string "skype", :default => "", :null => false
+ t.string "linkedin", :default => "", :null => false
+ t.string "twitter", :default => "", :null => false
t.string "authentication_token"
- t.boolean "dark_scheme", :default => false, :null => false
- t.integer "theme_id", :default => 1, :null => false
+ t.boolean "dark_scheme", :default => false, :null => false
+ t.integer "theme_id", :default => 1, :null => false
t.string "bio"
- t.boolean "blocked", :default => false, :null => false
- t.integer "failed_attempts", :default => 0
+ t.boolean "blocked", :default => false, :null => false
+ t.integer "failed_attempts", :default => 0
t.datetime "locked_at"
t.string "extern_uid"
t.string "provider"
diff --git a/vendor/assets/images/authbuttons/github_32.png b/vendor/assets/images/authbuttons/github_32.png
new file mode 100644
index 0000000000000000000000000000000000000000..247e52a5f4282110243afa350cd4a13b0154c2a1
Binary files /dev/null and b/vendor/assets/images/authbuttons/github_32.png differ
diff --git a/vendor/assets/images/authbuttons/github_64.png b/vendor/assets/images/authbuttons/github_64.png
new file mode 100644
index 0000000000000000000000000000000000000000..fca7bf44652470a58edd12b410613656da95aed3
Binary files /dev/null and b/vendor/assets/images/authbuttons/github_64.png differ
diff --git a/vendor/assets/images/authbuttons/google_32.png b/vendor/assets/images/authbuttons/google_32.png
new file mode 100644
index 0000000000000000000000000000000000000000..3909e9de93b22e1f3a2e6c264f6289331412a3bb
Binary files /dev/null and b/vendor/assets/images/authbuttons/google_32.png differ
diff --git a/vendor/assets/images/authbuttons/google_64.png b/vendor/assets/images/authbuttons/google_64.png
new file mode 100644
index 0000000000000000000000000000000000000000..e55f34f1b7d57c52172eb2bab0964037c532629b
Binary files /dev/null and b/vendor/assets/images/authbuttons/google_64.png differ
diff --git a/vendor/assets/images/authbuttons/twitter_32.png b/vendor/assets/images/authbuttons/twitter_32.png
new file mode 100644
index 0000000000000000000000000000000000000000..daadcffd315f11026cface9d99409997050ab9b9
Binary files /dev/null and b/vendor/assets/images/authbuttons/twitter_32.png differ
diff --git a/vendor/assets/images/authbuttons/twitter_64.png b/vendor/assets/images/authbuttons/twitter_64.png
new file mode 100644
index 0000000000000000000000000000000000000000..68b74530c06b558b6c4848c2637d4caeaf4c969b
Binary files /dev/null and b/vendor/assets/images/authbuttons/twitter_64.png differ