Commit 621affecb59b8ce5304370cfd7979fba2b73ff4e

Authored by Dmitriy Zaporozhets
2 parents 40eec08c 0dd94cd8

Merge branch 'master' of https://github.com/funglaub/gitlabhq into funglaub-master

Conflicts:
	Gemfile.lock
	app/helpers/application_helper.rb
	app/views/devise/sessions/new.html.erb
	db/schema.rb
@@ -16,6 +16,10 @@ gem "mysql2" @@ -16,6 +16,10 @@ gem "mysql2"
16 16
17 # Auth 17 # Auth
18 gem "devise", "~> 2.1.0" 18 gem "devise", "~> 2.1.0"
  19 +gem 'omniauth'
  20 +gem 'omniauth-google-oauth2'
  21 +gem 'omniauth-twitter'
  22 +gem 'omniauth-github'
19 23
20 # GITLAB patched libs 24 # GITLAB patched libs
21 gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837" 25 gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837"
app/assets/stylesheets/auth_methods.scss 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +.auth_methods {
  2 + &ul {
  3 + margin: 0;
  4 + text-align:center;
  5 + padding: 5px;
  6 + &li {
  7 + display: inline;
  8 + }
  9 + }
  10 +}
app/assets/stylesheets/main.scss
@@ -134,7 +134,7 @@ $hover: #fdf5d9; @@ -134,7 +134,7 @@ $hover: #fdf5d9;
134 * TODO: clean it 134 * TODO: clean it
135 */ 135 */
136 @import "common.scss"; 136 @import "common.scss";
137 - 137 +@import "auth_methods.scss";
138 138
139 /** 139 /**
140 * Styles related to specific part of app 140 * Styles related to specific part of app
app/controllers/omniauth_callbacks_controller.rb
@@ -9,7 +9,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController @@ -9,7 +9,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
9 error ||= env["omniauth.error.type"].to_s 9 error ||= env["omniauth.error.type"].to_s
10 error.to_s.humanize if error 10 error.to_s.humanize if error
11 end 11 end
12 - 12 +
13 def ldap 13 def ldap
14 # We only find ourselves here if the authentication to LDAP was successful. 14 # We only find ourselves here if the authentication to LDAP was successful.
15 @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user) 15 @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user)
@@ -19,4 +19,33 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController @@ -19,4 +19,33 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
19 sign_in_and_redirect @user 19 sign_in_and_redirect @user
20 end 20 end
21 21
  22 + Settings.omniauth_providers.each do |provider|
  23 + define_method provider['name'] do
  24 + handle_omniauth
  25 + end
  26 + end
  27 +
  28 + private
  29 +
  30 + def handle_omniauth
  31 + oauth = request.env['omniauth.auth']
  32 + provider, uid = oauth['provider'], oauth['uid']
  33 +
  34 + if current_user
  35 + # Change a logged-in user's authentication method:
  36 + current_user.extern_uid = uid
  37 + current_user.provider = provider
  38 + current_user.save
  39 + redirect_to profile_path
  40 + else
  41 + @user = User.find_or_new_for_omniauth(oauth)
  42 +
  43 + if @user
  44 + sign_in_and_redirect @user
  45 + else
  46 + flash[:notice] = "There's no such user!"
  47 + redirect_to new_user_session_path
  48 + end
  49 + end
  50 + end
22 end 51 end
app/helpers/application_helper.rb
@@ -135,4 +135,9 @@ module ApplicationHelper @@ -135,4 +135,9 @@ module ApplicationHelper
135 "Never" 135 "Never"
136 end 136 end
137 end 137 end
  138 +
  139 + def authbutton(provider, size = 64)
  140 + image_tag("authbuttons/#{provider.to_s.split('_').first}_#{size}.png",
  141 + alt: "Sign in with #{provider.to_s.titleize}" )
  142 + end
138 end 143 end
app/models/user.rb
@@ -86,10 +86,50 @@ class User < ActiveRecord::Base @@ -86,10 +86,50 @@ class User < ActiveRecord::Base
86 where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') 86 where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
87 end 87 end
88 88
  89 + def self.create_from_omniauth(auth, ldap = false)
  90 + provider, uid = auth.provider, auth.uid
  91 + name = auth.info.name.force_encoding("utf-8")
  92 + email = auth.info.email.downcase unless auth.info.email.nil?
  93 +
  94 + ldap_prefix = ldap ? '(LDAP) ' : ''
  95 + raise OmniAuth::Error, "#{ldap_prefix}#{provider} does not provide an email"\
  96 + " address" if auth.info.email.blank?
  97 +
  98 + logger.info "#{ldap_prefix}Creating user from #{provider} login"\
  99 + " {uid => #{uid}, name => #{name}, email => #{email}}"
  100 + password = Devise.friendly_token[0, 8].downcase
  101 + @user = User.new(
  102 + extern_uid: uid,
  103 + provider: provider,
  104 + name: name,
  105 + email: email,
  106 + password: password,
  107 + password_confirmation: password,
  108 + projects_limit: Gitlab.config.default_projects_limit,
  109 + )
  110 + if Gitlab.config.omniauth.block_auto_created_users && !ldap
  111 + @user.blocked = true
  112 + end
  113 + @user.save!
  114 + @user
  115 + end
  116 +
  117 + def self.find_or_new_for_omniauth(auth)
  118 + provider, uid = auth.provider, auth.uid
  119 +
  120 + if @user = User.find_by_provider_and_extern_uid(provider, uid)
  121 + @user
  122 + else
  123 + if Gitlab.config.omniauth.allow_single_sign_on
  124 + @user = User.create_from_omniauth(auth)
  125 + @user
  126 + end
  127 + end
  128 + end
  129 +
89 def self.find_for_ldap_auth(auth, signed_in_resource=nil) 130 def self.find_for_ldap_auth(auth, signed_in_resource=nil)
90 uid = auth.info.uid 131 uid = auth.info.uid
91 provider = auth.provider 132 provider = auth.provider
92 - name = auth.info.name.force_encoding("utf-8")  
93 email = auth.info.email.downcase unless auth.info.email.nil? 133 email = auth.info.email.downcase unless auth.info.email.nil?
94 raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil? 134 raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil?
95 135
@@ -101,17 +141,7 @@ class User < ActiveRecord::Base @@ -101,17 +141,7 @@ class User < ActiveRecord::Base
101 @user.update_attributes(:extern_uid => uid, :provider => provider) 141 @user.update_attributes(:extern_uid => uid, :provider => provider)
102 @user 142 @user
103 else 143 else
104 - logger.info "Creating user from LDAP login {uid => #{uid}, name => #{name}, email => #{email}}"  
105 - password = Devise.friendly_token[0, 8].downcase  
106 - @user = User.create(  
107 - :extern_uid => uid,  
108 - :provider => provider,  
109 - :name => name,  
110 - :email => email,  
111 - :password => password,  
112 - :password_confirmation => password,  
113 - :projects_limit => Gitlab.config.default_projects_limit  
114 - ) 144 + create_from_omniauth(auth)
115 end 145 end
116 end 146 end
117 147
@@ -148,4 +178,3 @@ end @@ -148,4 +178,3 @@ end
148 # bio :string(255) 178 # bio :string(255)
149 # blocked :boolean(1) default(FALSE), not null 179 # blocked :boolean(1) default(FALSE), not null
150 # 180 #
151 -  
app/views/devise/sessions/new.html.erb 0 → 100644
@@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
  1 +<% unless ldap_enable? -%>
  2 +
  3 + <%= form_for(resource, :as => resource_name, :url => session_path(resource_name), :html => { :class => "login-box" }) do |f| %>
  4 + <%= image_tag "login-logo.png", :width => "304", :height => "66", :class => "login-logo", :alt => "Login Logo" %>
  5 +
  6 + <%= f.text_field :email, :class => "text top", :placeholder => "Email" %>
  7 + <%= f.password_field :password, :class => "text bottom", :placeholder => "Password" %>
  8 +
  9 + <% if devise_mapping.rememberable? -%>
  10 + <div class="clearfix inputs-list"> <label class="checkbox remember_me" for="user_remember_me"><%= f.check_box :remember_me %><span>Remember me</span></label></div>
  11 + <% end -%>
  12 + <br/>
  13 + <%= f.submit "Sign in", :class => "primary btn" %>
  14 + <div class="right"> <%= render :partial => "devise/shared/links" %></div>
  15 +
  16 + <%- if devise_mapping.omniauthable? %>
  17 + <hr/>
  18 + <div class="auth_methods">
  19 + <ul>
  20 + <%- resource_class.omniauth_providers.each do |provider| %>
  21 + <li><%= link_to authbutton(provider),
  22 + omniauth_authorize_path(resource_name, provider) %></li>
  23 + <% end -%>
  24 + </ul>
  25 + </div>
  26 + <% end -%>
  27 +
  28 + <% end %>
  29 +
  30 +<% else %>
  31 + <%= render :partial => 'devise/sessions/new_ldap' %>
  32 +<% end %>
app/views/layouts/profile.html.haml
@@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
10 = link_to "Profile", profile_path 10 = link_to "Profile", profile_path
11 11
12 %li{class: tab_class(:password)} 12 %li{class: tab_class(:password)}
13 - = link_to "Password", profile_password_path 13 + = link_to "Authentication", profile_password_path
14 14
15 %li{class: tab_class(:ssh_keys)} 15 %li{class: tab_class(:ssh_keys)}
16 = link_to keys_path do 16 = link_to keys_path do
app/views/profile/password.html.haml
1 %h3.page_title Password 1 %h3.page_title Password
2 %hr 2 %hr
  3 +
3 = form_for @user, url: profile_password_path, method: :put do |f| 4 = form_for @user, url: profile_password_path, method: :put do |f|
4 - .data  
5 - %p.slead After successful password update you will be redirected to login page where you should login with new password  
6 - -if @user.errors.any?  
7 - .alert-message.block-message.error  
8 - %ul  
9 - - @user.errors.full_messages.each do |msg|  
10 - %li= msg 5 + .row
  6 + .span7
  7 + .data
  8 + %p.slead After successful password update you will be redirected to login page where you should login with new password
  9 + -if @user.errors.any?
  10 + .alert-message.block-message.error
  11 + %ul
  12 + - @user.errors.full_messages.each do |msg|
  13 + %li= msg
  14 +
  15 + .clearfix
  16 + = f.label :password
  17 + .input= f.password_field :password
  18 + .clearfix
  19 + = f.label :password_confirmation
  20 + .input= f.password_field :password_confirmation
11 21
12 - .clearfix  
13 - = f.label :password  
14 - .input= f.password_field :password  
15 - .clearfix  
16 - = f.label :password_confirmation  
17 - .input= f.password_field :password_confirmation 22 + - if Settings.omniauth.enabled
  23 + .span5.right
  24 + .auth_methods.alert.alert-info
  25 + %strong Tip: Use one of the following sites to login
  26 + %ul
  27 + - User.omniauth_providers.each do |provider|
  28 + %li= link_to authbutton(provider), |
  29 + omniauth_authorize_path(User, provider) |
18 .actions 30 .actions
19 = f.submit 'Save', class: "btn save-btn" 31 = f.submit 'Save', class: "btn save-btn"
app/views/profile/show.html.haml
@@ -50,6 +50,13 @@ @@ -50,6 +50,13 @@
50 %strong Tip: 50 %strong Tip:
51 You can change your avatar at gravatar.com 51 You can change your avatar at gravatar.com
52 52
  53 + - if Settings.omniauth.enabled && @user.provider?
  54 + %h4
  55 + Omniauth Providers:
  56 + = link_to "Change", profile_password_path, class: "btn small right"
  57 + You can login through #{@user.provider.titleize}!
  58 + = authbutton(@user.provider, 32)
  59 +
53 %h4 60 %h4
54 Personal projects: 61 Personal projects:
55 %small.right 62 %small.right
config/gitlab.yml.example
@@ -50,3 +50,21 @@ git: @@ -50,3 +50,21 @@ git:
50 git_max_size: 5242880 # 5.megabytes 50 git_max_size: 5242880 # 5.megabytes
51 # Git timeout to read commit, in seconds 51 # Git timeout to read commit, in seconds
52 git_timeout: 10 52 git_timeout: 10
  53 +
  54 +# Omniauth configuration
  55 +omniauth:
  56 + enabled: false
  57 + providers:
  58 + allow_single_sign_on: false
  59 + block_auto_created_users: true
  60 +
  61 +# omniauth:
  62 +# enabled: true
  63 +# providers:
  64 +# - { name: 'google_oauth2', app_id: 'YOUR APP ID',
  65 +# app_secret: 'YOUR APP SECRET',
  66 +# args: { access_type: 'offline', approval_prompt: '' } }
  67 +# - { name: 'twitter', app_id: 'YOUR APP ID',
  68 +# app_secret: 'YOUR APP SECRET'}
  69 +# - { name: 'github', app_id: 'YOUR APP ID',
  70 +# app_secret: 'YOUR APP SECRET' }
config/initializers/1_settings.rb
@@ -6,7 +6,7 @@ class Settings &lt; Settingslogic @@ -6,7 +6,7 @@ class Settings &lt; Settingslogic
6 self.web['protocol'] ||= web.https ? "https" : "http" 6 self.web['protocol'] ||= web.https ? "https" : "http"
7 end 7 end
8 8
9 - def web_host 9 + def web_host
10 self.web['host'] ||= 'localhost' 10 self.web['host'] ||= 'localhost'
11 end 11 end
12 12
@@ -14,11 +14,11 @@ class Settings &lt; Settingslogic @@ -14,11 +14,11 @@ class Settings &lt; Settingslogic
14 self.email['from'] ||= ("notify@" + web_host) 14 self.email['from'] ||= ("notify@" + web_host)
15 end 15 end
16 16
17 - def url 17 + def url
18 self['url'] ||= build_url 18 self['url'] ||= build_url
19 - end 19 + end
20 20
21 - def web_port 21 + def web_port
22 if web.https 22 if web.https
23 web['port'] = 443 23 web['port'] = 443
24 else 24 else
@@ -36,7 +36,7 @@ class Settings &lt; Settingslogic @@ -36,7 +36,7 @@ class Settings &lt; Settingslogic
36 raw_url << web_host 36 raw_url << web_host
37 37
38 if web_custom_port? 38 if web_custom_port?
39 - raw_url << ":#{web_port}" 39 + raw_url << ":#{web_port}"
40 end 40 end
41 41
42 raw_url 42 raw_url
@@ -120,6 +120,14 @@ class Settings &lt; Settingslogic @@ -120,6 +120,14 @@ class Settings &lt; Settingslogic
120 app['backup_keep_time'] || 0 120 app['backup_keep_time'] || 0
121 end 121 end
122 122
  123 + def omniauth_enabled?
  124 + omniauth['enabled'] || false
  125 + end
  126 +
  127 + def omniauth_providers
  128 + omniauth['providers'] || []
  129 + end
  130 +
123 def disable_gravatar? 131 def disable_gravatar?
124 app['disable_gravatar'] || false 132 app['disable_gravatar'] || false
125 end 133 end
vendor/assets/images/authbuttons/github_32.png 0 → 100644

1.89 KB

vendor/assets/images/authbuttons/github_64.png 0 → 100644

4.34 KB

vendor/assets/images/authbuttons/google_32.png 0 → 100644

1.58 KB

vendor/assets/images/authbuttons/google_64.png 0 → 100644

3.37 KB

vendor/assets/images/authbuttons/twitter_32.png 0 → 100644

1.41 KB

vendor/assets/images/authbuttons/twitter_64.png 0 → 100644

3.3 KB