Commit 64f026b2 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

Merge branch 'funglaub-master'

parents 40eec08c 048d47e6
...@@ -16,6 +16,10 @@ gem "mysql2" ...@@ -16,6 +16,10 @@ gem "mysql2"
# Auth # Auth
gem "devise", "~> 2.1.0" gem "devise", "~> 2.1.0"
gem 'omniauth'
gem 'omniauth-google-oauth2'
gem 'omniauth-twitter'
gem 'omniauth-github'
# GITLAB patched libs # GITLAB patched libs
gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837" gem "grit", :git => "https://github.com/gitlabhq/grit.git", :ref => "7f35cb98ff17d534a07e3ce6ec3d580f67402837"
......
...@@ -158,6 +158,8 @@ GEM ...@@ -158,6 +158,8 @@ GEM
factory_girl_rails (4.0.0) factory_girl_rails (4.0.0)
factory_girl (~> 4.0.0) factory_girl (~> 4.0.0)
railties (>= 3.0.0) railties (>= 3.0.0)
faraday (0.8.4)
multipart-post (~> 1.1)
ffaker (1.14.0) ffaker (1.14.0)
ffi (1.0.11) ffi (1.0.11)
foreman (0.47.0) foreman (0.47.0)
...@@ -194,6 +196,7 @@ GEM ...@@ -194,6 +196,7 @@ GEM
httparty (0.8.3) httparty (0.8.3)
multi_json (~> 1.0) multi_json (~> 1.0)
multi_xml multi_xml
httpauth (0.1)
i18n (0.6.1) i18n (0.6.1)
journey (1.0.4) journey (1.0.4)
jquery-rails (2.0.2) jquery-rails (2.0.2)
...@@ -203,6 +206,8 @@ GEM ...@@ -203,6 +206,8 @@ GEM
jquery-rails jquery-rails
railties (>= 3.1.0) railties (>= 3.1.0)
json (1.7.5) json (1.7.5)
jwt (0.1.5)
multi_json (>= 1.0)
kaminari (0.14.0) kaminari (0.14.0)
actionpack (>= 3.0.0) actionpack (>= 3.0.0)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
...@@ -225,12 +230,35 @@ GEM ...@@ -225,12 +230,35 @@ GEM
sprockets (~> 2.0) sprockets (~> 2.0)
multi_json (1.3.6) multi_json (1.3.6)
multi_xml (0.5.1) multi_xml (0.5.1)
multipart-post (1.1.5)
mysql2 (0.3.11) mysql2 (0.3.11)
net-ldap (0.2.2) net-ldap (0.2.2)
nokogiri (1.5.3) nokogiri (1.5.3)
oauth (0.4.7)
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) omniauth (1.1.0)
hashie (~> 1.2) hashie (~> 1.2)
rack rack
omniauth-github (1.0.3)
omniauth (~> 1.0)
omniauth-oauth2 (~> 1.1)
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.13)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
orm_adapter (0.3.0) orm_adapter (0.3.0)
polyglot (0.3.3) polyglot (0.3.3)
posix-spawn (0.3.6) posix-spawn (0.3.6)
...@@ -420,7 +448,11 @@ DEPENDENCIES ...@@ -420,7 +448,11 @@ DEPENDENCIES
linguist (~> 1.0.0)! linguist (~> 1.0.0)!
modernizr (= 2.5.3) modernizr (= 2.5.3)
mysql2 mysql2
omniauth
omniauth-github
omniauth-google-oauth2
omniauth-ldap! omniauth-ldap!
omniauth-twitter
pry pry
pygments.rb! pygments.rb!
rack-mini-profiler rack-mini-profiler
......
...@@ -142,4 +142,8 @@ ...@@ -142,4 +142,8 @@
border:none; border:none;
} }
} }
.ui-box-body {
padding:10px;
}
} }
...@@ -135,7 +135,6 @@ $hover: #fdf5d9; ...@@ -135,7 +135,6 @@ $hover: #fdf5d9;
*/ */
@import "common.scss"; @import "common.scss";
/** /**
* Styles related to specific part of app * Styles related to specific part of app
*/ */
......
class OmniauthCallbacksController < Devise::OmniauthCallbacksController class OmniauthCallbacksController < Devise::OmniauthCallbacksController
Gitlab.config.omniauth_providers.each do |provider|
define_method provider['name'] do
handle_omniauth
end
end
# Extend the standard message generation to accept our custom exception # Extend the standard message generation to accept our custom exception
def failure_message def failure_message
...@@ -9,7 +14,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -9,7 +14,7 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
error ||= env["omniauth.error.type"].to_s error ||= env["omniauth.error.type"].to_s
error.to_s.humanize if error error.to_s.humanize if error
end end
def ldap def ldap
# We only find ourselves here if the authentication to LDAP was successful. # We only find ourselves here if the authentication to LDAP was successful.
@user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user) @user = User.find_for_ldap_auth(request.env["omniauth.auth"], current_user)
...@@ -19,4 +24,27 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController ...@@ -19,4 +24,27 @@ class OmniauthCallbacksController < Devise::OmniauthCallbacksController
sign_in_and_redirect @user sign_in_and_redirect @user
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 end
...@@ -135,4 +135,10 @@ module ApplicationHelper ...@@ -135,4 +135,10 @@ module ApplicationHelper
"Never" "Never"
end end
end end
def authbutton(provider, size = 64)
file_name = "#{provider.to_s.split('_').first}_#{size}.png"
image_tag("authbuttons/#{file_name}",
alt: "Sign in with #{provider.to_s.titleize}")
end
end end
...@@ -86,33 +86,20 @@ class User < ActiveRecord::Base ...@@ -86,33 +86,20 @@ class User < ActiveRecord::Base
where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)') where('id NOT IN (SELECT DISTINCT(user_id) FROM users_projects)')
end end
def self.find_for_ldap_auth(auth, signed_in_resource=nil) def self.create_from_omniauth(auth, ldap = false)
uid = auth.info.uid gitlab_auth.create_from_omniauth(auth, ldap)
provider = auth.provider end
name = auth.info.name.force_encoding("utf-8")
email = auth.info.email.downcase unless auth.info.email.nil? def self.find_or_new_for_omniauth(auth)
raise OmniAuth::Error, "LDAP accounts must provide an uid and email address" if uid.nil? or email.nil? gitlab_auth.find_or_new_for_omniauth(auth)
end
if @user = User.find_by_extern_uid_and_provider(uid, provider)
@user def self.find_for_ldap_auth(auth, signed_in_resource = nil)
# workaround for backward compatibility gitlab_auth.find_for_ldap_auth(auth, signed_in_resource)
elsif @user = User.find_by_email(email) end
logger.info "Updating legacy LDAP user #{email} with extern_uid => #{uid}"
@user.update_attributes(:extern_uid => uid, :provider => provider) def self.gitlab_auth
@user Gitlab::Auth.new
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
)
end
end end
def self.search query def self.search query
...@@ -148,4 +135,3 @@ end ...@@ -148,4 +135,3 @@ end
# bio :string(255) # bio :string(255)
# blocked :boolean(1) default(FALSE), not null # blocked :boolean(1) default(FALSE), not null
# #
...@@ -15,7 +15,8 @@ ...@@ -15,7 +15,8 @@
.right .right
= render :partial => "devise/shared/links" = render :partial => "devise/shared/links"
- if devise_mapping.omniauthable? - if devise_mapping.omniauthable?
- resource_class.omniauth_providers.each do |provider| %hr/
%hr/ %ul.unstyled
= link_to "Sign in with #{provider.to_s.titleize}", omniauth_authorize_path(resource_name, provider), :class => "btn primary" - resource_class.omniauth_providers.each do |provider|
%br/ %li
= link_to authbutton(provider, 32), omniauth_authorize_path(resource_name, provider)
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
= link_to "Profile", profile_path = link_to "Profile", profile_path
%li{class: tab_class(:password)} %li{class: tab_class(:password)}
= link_to "Password", profile_password_path = link_to "Authentication", profile_password_path
%li{class: tab_class(:ssh_keys)} %li{class: tab_class(:ssh_keys)}
= link_to keys_path do = link_to keys_path do
......
%h3.page_title Password %h3.page_title Password
%hr %hr
= form_for @user, url: profile_password_path, method: :put do |f| = form_for @user, url: profile_password_path, method: :put do |f|
.data .row
%p.slead After successful password update you will be redirected to login page where you should login with new password .span7
-if @user.errors.any? .data
.alert-message.block-message.error %p.slead After successful password update you will be redirected to login page where you should login with new password
%ul -if @user.errors.any?
- @user.errors.full_messages.each do |msg| .alert-message.block-message.error
%li= msg %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 - if Gitlab.config.omniauth_enabled?
= f.label :password .span5.right
.input= f.password_field :password .alert.alert-info
.clearfix %strong Tip: Use one of the following sites to login
= f.label :password_confirmation %ul.unstyled
.input= f.password_field :password_confirmation - User.omniauth_providers.each do |provider|
%li= link_to authbutton(provider), |
omniauth_authorize_path(User, provider) |
.actions .actions
= f.submit 'Save', class: "btn save-btn" = f.submit 'Save', class: "btn save-btn"
...@@ -50,21 +50,34 @@ ...@@ -50,21 +50,34 @@
%strong Tip: %strong Tip:
You can change your avatar at gravatar.com You can change your avatar at gravatar.com
%h4 - @user.provider = 'twitter'
Personal projects: - if Gitlab.config.omniauth_enabled? && @user.provider?
%small.right .ui-box
%span= current_user.my_own_projects.count .ui-box-body
of %h4
%span= current_user.projects_limit Omniauth Providers:
.progress = link_to "Change", profile_password_path, class: "btn small right"
.bar{style: "width: #{current_user.projects_limit_percent}%;"} You can login through #{@user.provider.titleize}!
= authbutton(@user.provider, 32)
%h4 .ui-box
SSH public keys: .ui-box-body
%small.right %h4
%span= link_to current_user.keys.count, keys_path Personal projects:
%small.right
%span= current_user.my_own_projects.count
of
%span= current_user.projects_limit
.progress
.bar{style: "width: #{current_user.projects_limit_percent}%;"}
= link_to "Add Public Key", new_key_path, class: "btn small right" .ui-box
.ui-box-body
%h4
SSH public keys:
%strong.right= link_to current_user.keys.count, keys_path
= link_to "Add Public Key", new_key_path, class: "btn small"
.form-actions .form-actions
= f.submit 'Save', class: "btn save-btn" = f.submit 'Save', class: "btn save-btn"
...@@ -25,8 +25,45 @@ app: ...@@ -25,8 +25,45 @@ app:
# backup_keep_time: 604800 # default: 0 (forever) (in seconds) # backup_keep_time: 604800 # default: 0 (forever) (in seconds)
# disable_gravatar: true # default: false - Disable user avatars from Gravatar.com # disable_gravatar: true # default: false - Disable user avatars from Gravatar.com
#
# 2. Auth settings
# ==========================
ldap:
enabled: false
host: '_your_ldap_server'
base: '_the_base_where_you_search_for_users'
port: 636
uid: 'sAMAccountName'
method: 'ssl' # plain
bind_dn: '_the_full_dn_of_the_user_you_will_bind_with'
password: '_the_password_of_the_bind_user'
omniauth:
# Enable ability for users
# to login via twitter, google ..
enabled: true
# IMPORTANT!
# It allows user to login without having user account
allow_single_sign_on: false
block_auto_created_users: true
# Auth providers
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' }
# #
# 2. Advanced settings: # 3. Advanced settings:
# ========================== # ==========================
# Git Hosting configuration # Git Hosting configuration
......
...@@ -6,7 +6,7 @@ class Settings < Settingslogic ...@@ -6,7 +6,7 @@ class Settings < Settingslogic
self.web['protocol'] ||= web.https ? "https" : "http" self.web['protocol'] ||= web.https ? "https" : "http"
end end
def web_host def web_host
self.web['host'] ||= 'localhost' self.web['host'] ||= 'localhost'
end end
...@@ -14,11 +14,11 @@ class Settings < Settingslogic ...@@ -14,11 +14,11 @@ class Settings < Settingslogic
self.email['from'] ||= ("notify@" + web_host) self.email['from'] ||= ("notify@" + web_host)
end end
def url def url
self['url'] ||= build_url self['url'] ||= build_url
end end
def web_port def web_port
if web.https if web.https
web['port'] = 443 web['port'] = 443
else else
...@@ -36,7 +36,7 @@ class Settings < Settingslogic ...@@ -36,7 +36,7 @@ class Settings < Settingslogic
raw_url << web_host raw_url << web_host
if web_custom_port? if web_custom_port?
raw_url << ":#{web_port}" raw_url << ":#{web_port}"
end end
raw_url raw_url
...@@ -120,6 +120,22 @@ class Settings < Settingslogic ...@@ -120,6 +120,22 @@ class Settings < Settingslogic
app['backup_keep_time'] || 0 app['backup_keep_time'] || 0
end end
def ldap_enabled?
ldap['enabled']
rescue
false
end
def omniauth_enabled?
omniauth && omniauth['enabled']
rescue
false
end
def omniauth_providers
omniauth['providers'] || []
end
def disable_gravatar? def disable_gravatar?
app['disable_gravatar'] || false app['disable_gravatar'] || false
end end
......
...@@ -204,4 +204,21 @@ Devise.setup do |config| ...@@ -204,4 +204,21 @@ Devise.setup do |config|
# manager.intercept_401 = false # manager.intercept_401 = false
# manager.default_strategies(:scope => :user).unshift :some_external_strategy # manager.default_strategies(:scope => :user).unshift :some_external_strategy
# end # end
gl = Gitlab.config
if gl.ldap_enabled?
config.omniauth :ldap,
:host => gl.ldap['host'],
:base => gl.ldap['base'],
:uid => gl.ldap['uid'],
:port => gl.ldap['port'],
:method => gl.ldap['method'],
:bind_dn => gl.ldap['bind_dn'],
:password => gl.ldap['password']
end
gl.omniauth_providers.each do |gl_provider|
config.omniauth gl_provider['name'].to_sym, gl_provider['app_id'], gl_provider['app_secret']
end
end end
# Copy this file to 'omniauth.rb' and configure it as necessary.
# The wiki has further details on configuring each provider.
Devise.setup do |config|
# config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo'
# config.omniauth :ldap,
# :host => 'YOUR_LDAP_SERVER',
# :base => 'THE_BASE_WHERE_YOU_SEARCH_FOR_USERS',
# :uid => 'sAMAccountName',
# :port => 389,
# :method => :plain,
# :bind_dn => 'THE_FULL_DN_OF_THE_USER_YOU_WILL_BIND_WITH',
# :password => 'THE_PASSWORD_OF_THE_BIND_USER'
end
module Gitlab
class Auth
def find_for_ldap_auth(auth, signed_in_resource = nil)
uid = auth.info.uid
provider = auth.provider
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?
if @user = User.find_by_extern_uid_and_provider(uid, provider)
@user
elsif @user = User.find_by_email(email)
log.info "Updating legacy LDAP user #{email} with extern_uid => #{uid}"
@user.update_attributes(:extern_uid => uid, :provider => provider)
@user
else
create_from_omniauth(auth, true)
end
end
def create_from_omniauth auth, ldap = false
provider = auth.provider
uid = auth.info.uid || 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?
log.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 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 = create_from_omniauth(auth)
@user
end
end
end
def log
Gitlab::AppLogger
end
end
end
require 'spec_helper'
describe Gitlab::Auth do
let(:gl_auth) { Gitlab::Auth.new }
before do
@info = mock(
uid: '12djsak321',
name: 'John',
email: 'john@mail.com'
)
end
describe :find_for_ldap_auth do
before do
@auth = mock(
uid: '12djsak321',
info: @info,
provider: 'ldap'
)
end
it "should find by uid & provider" do
User.should_receive :find_by_extern_uid_and_provider
gl_auth.find_for_ldap_auth(@auth)
end
it "should update credentials by email if missing uid" do
user = double('User')
User.stub find_by_extern_uid_and_provider: nil
User.stub find_by_email: user
user.should_receive :update_attributes
gl_auth.find_for_ldap_auth(@auth)
end
it "should create from auth if user doesnot exist"do
User.stub find_by_extern_uid_and_provider: nil
User.stub find_by_email: nil
gl_auth.should_receive :create_from_omniauth
gl_auth.find_for_ldap_auth(@auth)
end
end
describe :find_or_new_for_omniauth do
before do
@auth = mock(
info: @info,
provider: 'twitter',
uid: '12djsak321',
)
end
it "should find user"do
User.should_receive :find_by_provider_and_extern_uid
gl_auth.should_not_receive :create_from_omniauth
gl_auth.find_or_new_for_omniauth(@auth)
end
it "should not create user"do
User.stub find_by_provider_and_extern_uid: nil
gl_auth.should_not_receive :create_from_omniauth
gl_auth.find_or_new_for_omniauth(@auth)
end
it "should create user if single_sing_on"do
Gitlab.config.omniauth.stub allow_single_sign_on: true
User.stub find_by_provider_and_extern_uid: nil
gl_auth.should_receive :create_from_omniauth
gl_auth.find_or_new_for_omniauth(@auth)
end
end
describe :create_from_omniauth do
it "should create user from LDAP" do
@auth = mock(info: @info, provider: 'ldap')
user = gl_auth.create_from_omniauth(@auth, true)
user.should be_valid
user.extern_uid.should == @info.uid
user.provider.should == 'ldap'
end
it "should create user from Omniauth" do
@auth = mock(info: @info, provider: 'twitter')
user = gl_auth.create_from_omniauth(@auth, false)
user.should be_valid
user.extern_uid.should == @info.uid
user.provider.should == 'twitter'
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment