Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
405a5acb
Commit
405a5acb
authored
Sep 15, 2014
by
Dmitriy Zaporozhets
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'feature-oauth-refactoring' into 'master'
Feature oauth refactoring See merge request !173
parents
9f93930f
f3346a47
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
190 additions
and
141 deletions
+190
-141
app/models/user.rb
app/models/user.rb
+0
-4
lib/gitlab/ldap/user.rb
lib/gitlab/ldap/user.rb
+33
-41
lib/gitlab/oauth/auth_hash.rb
lib/gitlab/oauth/auth_hash.rb
+54
-0
lib/gitlab/oauth/user.rb
lib/gitlab/oauth/user.rb
+53
-81
spec/lib/gitlab/auth_spec.rb
spec/lib/gitlab/auth_spec.rb
+30
-11
spec/lib/gitlab/ldap/user_spec.rb
spec/lib/gitlab/ldap/user_spec.rb
+20
-4
No files found.
app/models/user.rb
View file @
405a5acb
...
@@ -476,10 +476,6 @@ class User < ActiveRecord::Base
...
@@ -476,10 +476,6 @@ class User < ActiveRecord::Base
email
=~
/\Atemp-email-for-oauth/
email
=~
/\Atemp-email-for-oauth/
end
end
def
generate_tmp_oauth_email
self
.
email
=
"temp-email-for-oauth-
#{
username
}
@gitlab.localhost"
end
def
public_profile?
def
public_profile?
authorized_projects
.
public_only
.
any?
authorized_projects
.
public_only
.
any?
end
end
...
...
lib/gitlab/ldap/user.rb
View file @
405a5acb
...
@@ -10,37 +10,20 @@ module Gitlab
...
@@ -10,37 +10,20 @@ module Gitlab
module
LDAP
module
LDAP
class
User
<
Gitlab
::
OAuth
::
User
class
User
<
Gitlab
::
OAuth
::
User
class
<<
self
class
<<
self
def
find_or_create
(
auth
)
def
find_or_create
(
auth_hash
)
@auth
=
auth
self
.
auth_hash
=
auth_hash
find
(
auth_hash
)
||
find_and_connect_by_email
(
auth_hash
)
||
create
(
auth_hash
)
end
if
uid
.
blank?
||
email
.
blank?
||
username
.
blank?
def
find_and_connect_by_email
(
auth_hash
)
raise_error
(
"Account must provide a dn, uid and email address"
)
self
.
auth_hash
=
auth_hash
end
user
=
model
.
find_by
(
email:
self
.
auth_hash
.
email
)
user
=
find
(
auth
)
if
user
user
.
update_attributes
(
extern_uid:
auth_hash
.
uid
,
provider:
auth_hash
.
provider
)
unless
user
Gitlab
::
AppLogger
.
info
(
"(LDAP) Updating legacy LDAP user
#{
self
.
auth_hash
.
email
}
with extern_uid =>
#{
auth_hash
.
uid
}
"
)
# Look for user with same emails
return
user
#
# Possible cases:
# * When user already has account and need to link their LDAP account.
# * LDAP uid changed for user with same email and we need to update their uid
#
user
=
find_user
(
email
)
if
user
user
.
update_attributes
(
extern_uid:
uid
,
provider:
provider
)
log
.
info
(
"(LDAP) Updating legacy LDAP user
#{
email
}
with extern_uid =>
#{
uid
}
"
)
else
# Create a new user inside GitLab database
# based on LDAP credentials
#
#
user
=
create
(
auth
)
end
end
end
user
end
end
def
find_user
(
email
)
def
find_user
(
email
)
...
@@ -63,17 +46,8 @@ module Gitlab
...
@@ -63,17 +46,8 @@ module Gitlab
# Only check with valid login and password to prevent anonymous bind results
# Only check with valid login and password to prevent anonymous bind results
return
nil
unless
ldap_conf
.
enabled
&&
login
.
present?
&&
password
.
present?
return
nil
unless
ldap_conf
.
enabled
&&
login
.
present?
&&
password
.
present?
ldap
=
OmniAuth
::
LDAP
::
Adaptor
.
new
(
ldap_conf
)
ldap_user
=
adapter
.
bind_as
(
filter
=
Net
::
LDAP
::
Filter
.
eq
(
ldap
.
uid
,
login
)
filter:
user_filter
(
login
),
# Apply LDAP user filter if present
if
ldap_conf
[
'user_filter'
].
present?
user_filter
=
Net
::
LDAP
::
Filter
.
construct
(
ldap_conf
[
'user_filter'
])
filter
=
Net
::
LDAP
::
Filter
.
join
(
filter
,
user_filter
)
end
ldap_user
=
ldap
.
bind_as
(
filter:
filter
,
size:
1
,
size:
1
,
password:
password
password:
password
)
)
...
@@ -81,10 +55,14 @@ module Gitlab
...
@@ -81,10 +55,14 @@ module Gitlab
find_by_uid
(
ldap_user
.
dn
)
if
ldap_user
find_by_uid
(
ldap_user
.
dn
)
if
ldap_user
end
end
private
def
adapter
@adapter
||=
OmniAuth
::
LDAP
::
Adaptor
.
new
(
ldap_conf
)
end
protected
def
find_by_uid_and_provider
def
find_by_uid_and_provider
find_by_uid
(
uid
)
find_by_uid
(
auth_hash
.
uid
)
end
end
def
find_by_uid
(
uid
)
def
find_by_uid
(
uid
)
...
@@ -103,6 +81,20 @@ module Gitlab
...
@@ -103,6 +81,20 @@ module Gitlab
def
ldap_conf
def
ldap_conf
Gitlab
.
config
.
ldap
Gitlab
.
config
.
ldap
end
end
def
user_filter
(
login
)
filter
=
Net
::
LDAP
::
Filter
.
eq
(
adapter
.
uid
,
login
)
# Apply LDAP user filter if present
if
ldap_conf
[
'user_filter'
].
present?
user_filter
=
Net
::
LDAP
::
Filter
.
construct
(
ldap_conf
[
'user_filter'
])
filter
=
Net
::
LDAP
::
Filter
.
join
(
filter
,
user_filter
)
end
filter
end
end
def
needs_blocking?
false
end
end
end
end
end
end
...
...
lib/gitlab/oauth/auth_hash.rb
0 → 100644
View file @
405a5acb
# Class to parse and transform the info provided by omniauth
#
module
Gitlab
module
OAuth
class
AuthHash
attr_reader
:auth_hash
def
initialize
(
auth_hash
)
@auth_hash
=
auth_hash
end
def
uid
auth_hash
.
uid
.
to_s
end
def
provider
auth_hash
.
provider
end
def
info
auth_hash
.
info
end
def
name
(
info
.
name
||
full_name
).
to_s
.
force_encoding
(
'utf-8'
)
end
def
full_name
"
#{
info
.
first_name
}
#{
info
.
last_name
}
"
end
def
username
(
info
.
try
(
:nickname
)
||
generate_username
).
to_s
.
force_encoding
(
'utf-8'
)
end
def
email
(
info
.
try
(
:email
)
||
generate_temporarily_email
).
downcase
end
def
password
@password
||=
Devise
.
friendly_token
[
0
,
8
].
downcase
end
# Get the first part of the email address (before @)
# In addtion in removes illegal characters
def
generate_username
email
.
match
(
/^[^@]*/
)[
0
].
parameterize
end
def
generate_temporarily_email
"temp-email-for-oauth-
#{
username
}
@gitlab.localhost"
end
end
end
end
lib/gitlab/oauth/user.rb
View file @
405a5acb
...
@@ -7,106 +7,78 @@ module Gitlab
...
@@ -7,106 +7,78 @@ module Gitlab
module
OAuth
module
OAuth
class
User
class
User
class
<<
self
class
<<
self
attr_reader
:auth
attr_reader
:auth
_hash
def
find
(
auth
)
def
find
(
auth
_hash
)
@auth
=
aut
h
self
.
auth_hash
=
auth_has
h
find_by_uid_and_provider
find_by_uid_and_provider
end
end
def
create
(
auth
)
def
create
(
auth_hash
)
@auth
=
auth
user
=
new
(
auth_hash
)
password
=
Devise
.
friendly_token
[
0
,
8
].
downcase
user
.
save_and_trigger_callbacks
opts
=
{
end
extern_uid:
uid
,
provider:
provider
,
name:
name
,
username:
username
,
email:
email
,
password:
password
,
password_confirmation:
password
,
}
user
=
model
.
build_user
(
opts
)
user
.
skip_confirmation!
# Services like twitter and github does not return email via oauth
# In this case we generate temporary email and force user to fill it later
if
user
.
email
.
blank?
user
.
generate_tmp_oauth_email
elsif
provider
!=
"ldap"
# Google oauth returns email but dont return nickname
# So we use part of email as username for new user
# For LDAP, username is already set to the user's
# uid/userid/sAMAccountName.
email_username
=
email
.
match
(
/^[^@]*/
)[
0
]
# Strip apostrophes since they are disallowed as part of username
user
.
username
=
email_username
.
gsub
(
"'"
,
""
)
end
begin
user
.
save!
rescue
ActiveRecord
::
RecordInvalid
=>
e
log
.
info
"(OAuth) Email
#{
e
.
record
.
errors
[
:email
]
}
. Username
#{
e
.
record
.
errors
[
:username
]
}
"
return
nil
,
e
.
record
.
errors
end
log
.
info
"(OAuth) Creating user
#{
email
}
from login with extern_uid =>
#{
uid
}
"
if
Gitlab
.
config
.
omniauth
[
'block_auto_created_users'
]
&&
!
ldap?
user
.
block
end
user
def
model
::
User
end
end
private
def
auth_hash
=
(
auth_hash
)
@auth_hash
=
AuthHash
.
new
(
auth_hash
)
end
protected
def
find_by_uid_and_provider
def
find_by_uid_and_provider
model
.
where
(
provider:
provider
,
extern_uid:
uid
).
last
model
.
where
(
provider:
auth_hash
.
provider
,
extern_uid:
auth_hash
.
uid
).
last
end
end
end
def
uid
# Instance methods
auth
.
uid
.
to_s
attr_accessor
:auth_hash
,
:user
end
def
email
def
initialize
(
auth_hash
)
return
unless
auth
.
info
.
respond_to?
(
:email
)
self
.
auth_hash
=
auth_hash
auth
.
info
.
email
.
downcase
unless
auth
.
info
.
email
.
nil?
self
.
user
=
self
.
class
.
model
.
new
(
user_attributes
)
end
user
.
skip_confirmation!
end
def
name
def
auth_hash
=
(
auth_hash
)
if
auth
.
info
.
name
.
nil?
@auth_hash
=
AuthHash
.
new
(
auth_hash
)
"
#{
auth
.
info
.
first_name
}
#{
auth
.
info
.
last_name
}
"
.
force_encoding
(
'utf-8'
)
end
else
auth
.
info
.
name
.
to_s
.
force_encoding
(
'utf-8'
)
end
end
def
username
def
save_and_trigger_callbacks
return
unless
auth
.
info
.
respond_to?
(
:nickname
)
user
.
save!
auth
.
info
.
nickname
.
to_s
.
force_encoding
(
"utf-8"
)
log
.
info
"(OAuth) Creating user
#{
auth_hash
.
email
}
from login with extern_uid =>
#{
auth_hash
.
uid
}
"
end
user
.
block
if
needs_blocking?
def
provider
user
auth
.
provider
rescue
ActiveRecord
::
RecordInvalid
=>
e
end
log
.
info
"(OAuth) Email
#{
e
.
record
.
errors
[
:email
]
}
. Username
#{
e
.
record
.
errors
[
:username
]
}
"
return
nil
,
e
.
record
.
errors
end
def
log
def
user_attributes
Gitlab
::
AppLogger
{
end
extern_uid:
auth_hash
.
uid
,
provider:
auth_hash
.
provider
,
name:
auth_hash
.
name
,
username:
auth_hash
.
username
,
email:
auth_hash
.
email
,
password:
auth_hash
.
password
,
password_confirmation:
auth_hash
.
password
,
}
end
def
model
def
log
::
Us
er
Gitlab
::
AppLogg
er
end
end
def
raise_error
(
message
)
def
raise_error
(
message
)
raise
OmniAuth
::
Error
,
"(OAuth) "
+
message
raise
OmniAuth
::
Error
,
"(OAuth) "
+
message
end
end
def
ldap?
def
needs_blocking?
provider
==
'ldap'
Gitlab
.
config
.
omniauth
[
'block_auto_created_users'
]
end
end
end
end
end
end
end
...
...
spec/lib/gitlab/auth_spec.rb
View file @
405a5acb
...
@@ -4,25 +4,44 @@ describe Gitlab::Auth do
...
@@ -4,25 +4,44 @@ describe Gitlab::Auth do
let
(
:gl_auth
)
{
Gitlab
::
Auth
.
new
}
let
(
:gl_auth
)
{
Gitlab
::
Auth
.
new
}
describe
:find
do
describe
:find
do
before
do
let!
(
:user
)
do
@user
=
create
(
create
(
:user
,
:user
,
username:
username
,
username:
'john'
,
password:
password
,
password:
'88877711'
,
password_confirmation:
password
)
password_confirmation:
'88877711'
)
end
end
let
(
:username
)
{
'john'
}
let
(
:password
)
{
'my-secret'
}
it
"should find user by valid login/password"
do
it
"should find user by valid login/password"
do
gl_auth
.
find
(
'john'
,
'88877711'
).
should
==
@
user
expect
(
gl_auth
.
find
(
username
,
password
)
).
to
eql
user
end
end
it
"should not find user with invalid password"
do
it
"should not find user with invalid password"
do
gl_auth
.
find
(
'john'
,
'invalid11'
).
should_not
==
@user
password
=
'wrong'
expect
(
gl_auth
.
find
(
username
,
password
)
).
to_not
eql
user
end
end
it
"should not find user with invalid login and password"
do
it
"should not find user with invalid login"
do
gl_auth
.
find
(
'jon'
,
'invalid11'
).
should_not
==
@user
user
=
'wrong'
expect
(
gl_auth
.
find
(
username
,
password
)
).
to_not
eql
user
end
context
"with ldap enabled"
do
before
{
Gitlab
.
config
.
ldap
[
'enabled'
]
=
true
}
after
{
Gitlab
.
config
.
ldap
[
'enabled'
]
=
false
}
it
"tries to autheticate with db before ldap"
do
expect
(
Gitlab
::
LDAP
::
User
).
not_to
receive
(
:authenticate
)
gl_auth
.
find
(
username
,
password
)
end
it
"uses ldap as fallback to for authentication"
do
expect
(
Gitlab
::
LDAP
::
User
).
to
receive
(
:authenticate
)
gl_auth
.
find
(
'ldap_user'
,
'password'
)
end
end
end
end
end
end
end
spec/lib/gitlab/ldap/user_spec.rb
View file @
405a5acb
require
'spec_helper'
require
'spec_helper'
describe
Gitlab
::
LDAP
::
User
do
describe
Gitlab
::
LDAP
::
User
do
let
(
:gl_
auth
)
{
Gitlab
::
LDAP
::
User
}
let
(
:gl_
user
)
{
Gitlab
::
LDAP
::
User
}
let
(
:info
)
do
let
(
:info
)
do
double
(
double
(
name:
'John'
,
name:
'John'
,
...
@@ -19,12 +19,12 @@ describe Gitlab::LDAP::User do
...
@@ -19,12 +19,12 @@ describe Gitlab::LDAP::User do
it
"finds the user if already existing"
do
it
"finds the user if already existing"
do
existing_user
=
create
(
:user
,
extern_uid:
'my-uid'
,
provider:
'ldap'
)
existing_user
=
create
(
:user
,
extern_uid:
'my-uid'
,
provider:
'ldap'
)
expect
{
gl_
auth
.
find_or_create
(
auth
)
}.
to_not
change
{
User
.
count
}
expect
{
gl_
user
.
find_or_create
(
auth
)
}.
to_not
change
{
User
.
count
}
end
end
it
"connects to existing non-ldap user if the email matches"
do
it
"connects to existing non-ldap user if the email matches"
do
existing_user
=
create
(
:user
,
email:
'john@example.com'
)
existing_user
=
create
(
:user
,
email:
'john@example.com'
)
expect
{
gl_
auth
.
find_or_create
(
auth
)
}.
to_not
change
{
User
.
count
}
expect
{
gl_
user
.
find_or_create
(
auth
)
}.
to_not
change
{
User
.
count
}
existing_user
.
reload
existing_user
.
reload
expect
(
existing_user
.
extern_uid
).
to
eql
'my-uid'
expect
(
existing_user
.
extern_uid
).
to
eql
'my-uid'
...
@@ -32,7 +32,23 @@ describe Gitlab::LDAP::User do
...
@@ -32,7 +32,23 @@ describe Gitlab::LDAP::User do
end
end
it
"creates a new user if not found"
do
it
"creates a new user if not found"
do
expect
{
gl_auth
.
find_or_create
(
auth
)
}.
to
change
{
User
.
count
}.
by
(
1
)
expect
{
gl_user
.
find_or_create
(
auth
)
}.
to
change
{
User
.
count
}.
by
(
1
)
end
end
describe
"authenticate"
do
let
(
:login
)
{
'john'
}
let
(
:password
)
{
'my-secret'
}
before
{
Gitlab
.
config
.
ldap
[
'enabled'
]
=
true
Gitlab
.
config
.
ldap
[
'user_filter'
]
=
'employeeType=developer'
}
after
{
Gitlab
.
config
.
ldap
[
'enabled'
]
=
false
}
it
"send an authentication request to ldap"
do
expect
(
Gitlab
::
LDAP
::
User
.
adapter
).
to
receive
(
:bind_as
)
Gitlab
::
LDAP
::
User
.
authenticate
(
login
,
password
)
end
end
end
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment