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
092c678a
Commit
092c678a
authored
Feb 27, 2019
by
James Lopez
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update SCIM API and spec
parent
c89f993b
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
209 additions
and
19 deletions
+209
-19
ee/lib/api/scim.rb
ee/lib/api/scim.rb
+88
-14
ee/lib/ee/gitlab/scim/params_parser.rb
ee/lib/ee/gitlab/scim/params_parser.rb
+1
-1
ee/spec/requests/api/scim_spec.rb
ee/spec/requests/api/scim_spec.rb
+120
-4
No files found.
ee/lib/api/scim.rb
View file @
092c678a
...
...
@@ -11,39 +11,113 @@ module API
requires
:group
,
type:
String
end
helpers
do
def
logger
API
.
logger
end
def
destroy_identity
(
identity
)
GroupSaml
::
Identity
::
DestroyService
.
new
(
identity
).
execute
true
rescue
=>
e
logger
.
error
(
e
.
message
)
false
end
def
scim_not_found!
(
message
:)
error!
({
with:
EE
::
Gitlab
::
Scim
::
NotFound
}.
merge
(
detail:
message
),
404
)
end
def
scim_error!
(
message
:)
error!
({
with:
EE
::
Gitlab
::
Scim
::
Error
}.
merge
(
detail:
message
),
409
)
end
end
resource
:Users
do
before
do
check_group_saml_configured
authenticate!
end
desc
'Returns 200 if authenticated'
get
do
group
=
find_group!
(
params
[
:group
])
group
=
find_group
(
params
[
:group
])
scim_error!
(
message:
'Missing filter params'
)
unless
params
[
:filter
]
authorize_manage_saml!
(
group
)
parsed_hash
=
EE
::
Gitlab
::
Scim
::
ParamsParser
.
new
(
params
).
to_hash
identity
=
GroupSamlIdentityFinder
.
find_by_group_and_uid
(
group:
group
,
uid:
parsed_hash
[
:extern_uid
])
status
200
{}
# Dummy, just used to verify the connection by IdPs at the moment
present
identity
||
{},
with:
::
EE
::
Gitlab
::
Scim
::
Users
end
desc
'Removes a SAML user'
params
do
requires
:external_id
,
type:
Integer
,
desc:
'The external ID of the member'
get
':id'
do
group
=
find_group
(
params
[
:group
])
identity
=
GroupSamlIdentityFinder
.
find_by_group_and_uid
(
group:
group
,
uid:
params
[
:id
])
scim_not_found!
(
message:
"Resource
#{
params
[
:id
]
}
not found"
)
unless
identity
status
200
present
identity
,
with:
::
EE
::
Gitlab
::
Scim
::
User
end
delete
":external_id"
do
group
=
find_group!
(
params
[
:group
])
authorize_manage_saml!
(
group
)
# rubocop: disable CodeReuse/ActiveRecord
patch
':id'
do
scim_error!
(
message:
'Missing ID'
)
unless
params
[
:id
]
group
=
find_group
(
params
[
:group
])
parser
=
EE
::
Gitlab
::
Scim
::
ParamsParser
.
new
(
params
)
parsed_hash
=
parser
.
to_hash
identity
=
GroupSamlIdentityFinder
.
find_by_group_and_uid
(
group:
group
,
uid:
params
[
:id
])
scim_not_found!
(
message:
"Resource
#{
params
[
:id
]
}
not found"
)
unless
identity
updated
=
if
parser
.
deprovision_user?
destroy_identity
(
identity
)
elsif
parsed_hash
[
:extern_uid
]
identity
.
update
(
parsed_hash
.
slice
(
:extern_uid
))
else
scim_error!
(
message:
'Email has already been taken'
)
if
parsed_hash
[
:email
]
&&
User
.
by_any_email
(
parsed_hash
[
:email
].
downcase
).
where
.
not
(
id:
identity
.
user
.
id
).
count
>
0
result
=
::
Users
::
UpdateService
.
new
(
identity
.
user
,
parsed_hash
.
except
(
:extern_uid
,
:provider
)
.
merge
(
user:
identity
.
user
)).
execute
result
[
:status
]
==
:success
end
if
updated
status
204
{}
else
scim_error!
(
message:
"Error updating
#{
identity
.
user
.
name
}
with
#{
parsed_hash
.
inspect
}
"
)
end
end
# rubocop: enable CodeReuse/ActiveRecord
desc
'Removes a SAML user'
delete
":id"
do
scim_error!
(
message:
'Missing ID'
)
unless
params
[
:id
]
group
=
find_group
(
params
[
:group
])
identity
=
GroupSamlIdentityFinder
.
find_by_group_and_uid
(
group:
group
,
uid:
params
[
:id
])
user
=
User
.
find_by_email
(
params
[
:external_id
])
scim_not_found!
(
message:
"Resource
#{
params
[
:id
]
}
not found"
)
unless
identity
not_found!
(
'User'
)
unless
user
status
204
linked_identity
=
GroupSamlIdentityFinder
.
new
(
user:
user
).
find_linked
(
group:
group
)
scim_not_found!
(
message:
"Resource
#{
params
[
:id
]
}
not found"
)
unless
destroy_identity
(
identity
)
GroupSaml
::
Identity
::
DestroyService
.
new
(
linked_identity
).
execute
{}
end
end
end
...
...
ee/lib/ee/gitlab/scim/params_parser.rb
View file @
092c678a
...
...
@@ -21,7 +21,7 @@ module EE
def
initialize
(
params
)
@filter
=
params
[
:filter
]
@operations
=
params
[
:
o
perations
]
@operations
=
params
[
:
O
perations
]
end
def
deprovision_user?
...
...
ee/spec/requests/api/scim_spec.rb
View file @
092c678a
...
...
@@ -6,7 +6,6 @@ describe API::Scim do
let
(
:user
)
{
create
(
:user
)
}
let
(
:identity
)
{
create
(
:group_saml_identity
,
user:
user
)
}
let
(
:group
)
{
identity
.
saml_provider
.
group
}
let
(
:token
)
{
create
(
:personal_access_token
,
user:
user
)
}
before
do
stub_licensed_features
(
group_saml:
true
)
...
...
@@ -15,10 +14,127 @@ describe API::Scim do
end
describe
'GET api/scim/v2/groups/:group/Users'
do
it
'responds with a
200
'
do
get
api
(
"scim/v2/groups/
#{
group
.
full_path
}
/Users"
,
user
,
oauth_access_token:
token
,
version:
''
)
it
'responds with a
n error if there is no filter
'
do
get
api
(
"scim/v2/groups/
#{
group
.
full_path
}
/Users"
,
user
,
version:
''
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
response
).
to
have_gitlab_http_status
(
409
)
end
context
'existing user'
do
it
'responds with 200'
do
get
api
(
"scim/v2/groups/
#{
group
.
full_path
}
/Users?filter=id eq
\"
#{
identity
.
extern_uid
}
\"
"
,
user
,
version:
''
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
json_response
[
'Resources'
]).
not_to
be_empty
expect
(
json_response
[
'totalResults'
]).
to
eq
(
1
)
end
end
context
'no user'
do
it
'responds with 200'
do
get
api
(
"scim/v2/groups/
#{
group
.
full_path
}
/Users?filter=id eq
\"
nonexistent
\"
"
,
user
,
version:
''
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
json_response
[
'Resources'
]).
to
be_empty
expect
(
json_response
[
'totalResults'
]).
to
eq
(
0
)
end
end
end
describe
'GET api/scim/v2/groups/:group/Users/:id'
do
it
'responds with 404 if there is no user'
do
get
api
(
"scim/v2/groups/
#{
group
.
full_path
}
/Users/123"
,
user
,
version:
''
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
context
'existing user'
do
it
'responds with 200'
do
get
api
(
"scim/v2/groups/
#{
group
.
full_path
}
/Users/
#{
identity
.
extern_uid
}
"
,
user
,
version:
''
)
expect
(
response
).
to
have_gitlab_http_status
(
200
)
expect
(
json_response
[
'id'
]).
to
eq
(
identity
.
extern_uid
)
end
end
end
describe
'PATCH api/scim/v2/groups/:group/Users/:id'
do
it
'responds with 404 if there is no user'
do
patch
api
(
"scim/v2/groups/
#{
group
.
full_path
}
/Users/123"
,
user
,
version:
''
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
end
context
'existing user'
do
context
'extern UID'
do
before
do
params
=
{
Operations
:
[{
'op'
:
'Replace'
,
'path'
:
'id'
,
'value'
:
'new_uid'
}]
}.
to_query
patch
api
(
"scim/v2/groups/
#{
group
.
full_path
}
/Users/
#{
identity
.
extern_uid
}
?
#{
params
}
"
,
user
,
version:
''
)
end
it
'responds with 204'
do
expect
(
response
).
to
have_gitlab_http_status
(
204
)
end
it
'updates the extern_uid'
do
expect
(
identity
.
reload
.
extern_uid
).
to
eq
(
'new_uid'
)
end
end
context
'name'
do
before
do
params
=
{
Operations
:
[{
'op'
:
'Replace'
,
'path'
:
'name.formatted'
,
'value'
:
'new_name'
}]
}.
to_query
patch
api
(
"scim/v2/groups/
#{
group
.
full_path
}
/Users/
#{
identity
.
extern_uid
}
?
#{
params
}
"
,
user
,
version:
''
)
end
it
'responds with 204'
do
expect
(
response
).
to
have_gitlab_http_status
(
204
)
end
it
'updates the name'
do
expect
(
user
.
reload
.
name
).
to
eq
(
'new_name'
)
end
end
context
'Remove user'
do
before
do
params
=
{
Operations
:
[{
'op'
:
'Replace'
,
'path'
:
'active'
,
'value'
:
'False'
}]
}.
to_query
patch
api
(
"scim/v2/groups/
#{
group
.
full_path
}
/Users/
#{
identity
.
extern_uid
}
?
#{
params
}
"
,
user
,
version:
''
)
end
it
'responds with 204'
do
expect
(
response
).
to
have_gitlab_http_status
(
204
)
end
it
'removes the identity link'
do
expect
{
identity
.
reload
}.
to
raise_error
(
ActiveRecord
::
RecordNotFound
)
end
end
end
end
describe
'DELETE/scim/v2/groups/:group/Users/:id'
do
context
'existing user'
do
before
do
delete
api
(
"scim/v2/groups/
#{
group
.
full_path
}
/Users/
#{
identity
.
extern_uid
}
"
,
user
,
version:
''
)
end
it
'responds with 204'
do
expect
(
response
).
to
have_gitlab_http_status
(
204
)
end
it
'removes the identity link'
do
expect
{
identity
.
reload
}.
to
raise_error
(
ActiveRecord
::
RecordNotFound
)
end
end
it
'responds with 404 if there is no user'
do
delete
api
(
"scim/v2/groups/
#{
group
.
full_path
}
/Users/123"
,
user
,
version:
''
)
expect
(
response
).
to
have_gitlab_http_status
(
404
)
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