Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
heptapod
heptapod
Commits
466db9af8874
Commit
466db9af
authored
Oct 05, 2018
by
Tuomo Ala-Vannesluoma
Browse files
Make GitLab pages support access control
parent
bf17807bde95
Changes
27
Hide whitespace changes
Inline
Side-by-side
GITLAB_PAGES_VERSION
View file @
466db9af
1.
1
.0
1.
2
.0
app/assets/javascripts/pages/projects/shared/permissions/components/settings_panel.vue
View file @
466db9af
...
...
@@ -52,6 +52,21 @@
required
:
false
,
default
:
''
,
},
pagesAvailable
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
pagesAccessControlEnabled
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
pagesHelpPath
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
},
data
()
{
...
...
@@ -64,6 +79,7 @@
buildsAccessLevel
:
20
,
wikiAccessLevel
:
20
,
snippetsAccessLevel
:
20
,
pagesAccessLevel
:
20
,
containerRegistryEnabled
:
true
,
lfsEnabled
:
true
,
requestAccessEnabled
:
true
,
...
...
@@ -90,6 +106,13 @@
);
},
pagesFeatureAccessLevelOptions
()
{
if
(
this
.
visibilityLevel
!==
visibilityOptions
.
PUBLIC
)
{
return
this
.
featureAccessLevelOptions
.
concat
([[
30
,
'
Everyone
'
]]);
}
return
this
.
featureAccessLevelOptions
;
},
repositoryEnabled
()
{
return
this
.
repositoryAccessLevel
>
0
;
},
...
...
@@ -109,6 +132,10 @@
this
.
buildsAccessLevel
=
Math
.
min
(
10
,
this
.
buildsAccessLevel
);
this
.
wikiAccessLevel
=
Math
.
min
(
10
,
this
.
wikiAccessLevel
);
this
.
snippetsAccessLevel
=
Math
.
min
(
10
,
this
.
snippetsAccessLevel
);
if
(
this
.
pagesAccessLevel
===
20
)
{
// When from Internal->Private narrow access for only members
this
.
pagesAccessLevel
=
10
;
}
this
.
highlightChanges
();
}
else
if
(
oldValue
===
visibilityOptions
.
PRIVATE
)
{
// if changing away from private, make enabled features more permissive
...
...
@@ -118,6 +145,7 @@
if
(
this
.
buildsAccessLevel
>
0
)
this
.
buildsAccessLevel
=
20
;
if
(
this
.
wikiAccessLevel
>
0
)
this
.
wikiAccessLevel
=
20
;
if
(
this
.
snippetsAccessLevel
>
0
)
this
.
snippetsAccessLevel
=
20
;
if
(
this
.
pagesAccessLevel
===
10
)
this
.
pagesAccessLevel
=
20
;
this
.
highlightChanges
();
}
},
...
...
@@ -323,6 +351,18 @@
name=
"project[project_feature_attributes][snippets_access_level]"
/>
</project-setting-row>
<project-setting-row
v-if=
"pagesAvailable && pagesAccessControlEnabled"
:help-path=
"pagesHelpPath"
label=
"Pages"
help-text=
"Static website for the project."
>
<project-feature-setting
v-model=
"pagesAccessLevel"
:options=
"pagesFeatureAccessLevelOptions"
name=
"project[project_feature_attributes][pages_access_level]"
/>
</project-setting-row>
</div>
</div>
</
template
>
app/controllers/projects_controller.rb
View file @
466db9af
...
...
@@ -366,6 +366,7 @@
repository_access_level
snippets_access_level
wiki_access_level
pages_access_level
]
]
end
...
...
app/graphql/types/permission_types/project.rb
View file @
466db9af
...
...
@@ -16,7 +16,7 @@
:create_deployment
,
:push_to_delete_protected_branch
,
:admin_wiki
,
:admin_project
,
:update_pages
,
:admin_remote_mirror
,
:create_label
,
:update_wiki
,
:destroy_wiki
,
:create_pages
,
:destroy_pages
:create_pages
,
:destroy_pages
,
:read_pages_content
end
end
end
app/helpers/projects_helper.rb
View file @
466db9af
...
...
@@ -454,6 +454,7 @@
buildsAccessLevel:
feature
.
builds_access_level
,
wikiAccessLevel:
feature
.
wiki_access_level
,
snippetsAccessLevel:
feature
.
snippets_access_level
,
pagesAccessLevel:
feature
.
pages_access_level
,
containerRegistryEnabled:
!!
project
.
container_registry_enabled
,
lfsEnabled:
!!
project
.
lfs_enabled
}
...
...
@@ -468,7 +469,10 @@
registryAvailable:
Gitlab
.
config
.
registry
.
enabled
,
registryHelpPath:
help_page_path
(
'user/project/container_registry'
),
lfsAvailable:
Gitlab
.
config
.
lfs
.
enabled
,
lfsHelpPath:
help_page_path
(
'workflow/lfs/manage_large_binaries_with_git_lfs'
)
lfsHelpPath:
help_page_path
(
'workflow/lfs/manage_large_binaries_with_git_lfs'
),
pagesAvailable:
Gitlab
.
config
.
pages
.
enabled
,
pagesAccessControlEnabled:
Gitlab
.
config
.
pages
.
access_control
,
pagesHelpPath:
help_page_path
(
'user/project/pages/index.md'
)
}
end
...
...
app/models/project.rb
View file @
466db9af
...
...
@@ -55,8 +55,8 @@
cache_markdown_field
:description
,
pipeline: :description
delegate
:feature_available?
,
:builds_enabled?
,
:wiki_enabled?
,
:merge_requests_enabled?
,
:issues_enabled?
,
to: :project_feature
,
allow_nil:
true
:merge_requests_enabled?
,
:issues_enabled?
,
:pages_enabled?
,
:public_pages?
,
to: :project_feature
,
allow_nil:
true
delegate
:base_dir
,
:disk_path
,
:ensure_storage_path_exists
,
to: :storage
...
...
@@ -356,7 +356,7 @@
# "enabled" here means "not disabled". It includes private features!
scope
:with_feature_enabled
,
->
(
feature
)
{
access_level_attribute
=
ProjectFeature
.
access_level_attribute
(
feature
)
with_project_feature
.
where
(
project_features:
{
access_level_attribute
=>
[
nil
,
ProjectFeature
::
PRIVATE
,
ProjectFeature
::
ENABLED
]
})
with_project_feature
.
where
(
project_features:
{
access_level_attribute
=>
[
nil
,
ProjectFeature
::
PRIVATE
,
ProjectFeature
::
ENABLED
,
ProjectFeature
::
PUBLIC
]
})
}
# Picks a feature where the level is exactly that given.
...
...
@@ -418,5 +418,5 @@
end
end
# project features may be "disabled", "internal"
or
"enabled". If "internal",
# project features may be "disabled", "internal"
,
"enabled"
or "public"
. If "internal",
# they are only available to team members. This scope returns projects where
...
...
@@ -422,7 +422,7 @@
# they are only available to team members. This scope returns projects where
# the feature is either enabled, or internal with permission for the user.
# the feature is either
public,
enabled, or internal with permission for the user.
#
# This method uses an optimised version of `with_feature_access_level` for
# logged in users to more efficiently get private projects with the given
# feature.
def
self
.
with_feature_available_for_user
(
feature
,
user
)
...
...
@@ -424,9 +424,9 @@
#
# This method uses an optimised version of `with_feature_access_level` for
# logged in users to more efficiently get private projects with the given
# feature.
def
self
.
with_feature_available_for_user
(
feature
,
user
)
visible
=
[
nil
,
ProjectFeature
::
ENABLED
]
visible
=
[
nil
,
ProjectFeature
::
ENABLED
,
ProjectFeature
::
PUBLIC
]
if
user
&
.
admin?
with_feature_enabled
(
feature
)
...
...
app/models/project_feature.rb
View file @
466db9af
...
...
@@ -13,9 +13,10 @@
# Disabled: not enabled for anyone
# Private: enabled only for team members
# Enabled: enabled for everyone able to access the project
# Public: enabled for everyone (only allowed for pages)
#
# Permission levels
DISABLED
=
0
PRIVATE
=
10
ENABLED
=
20
...
...
@@ -16,7 +17,8 @@
#
# Permission levels
DISABLED
=
0
PRIVATE
=
10
ENABLED
=
20
PUBLIC
=
30
...
...
@@ -22,5 +24,5 @@
FEATURES
=
%i(issues merge_requests wiki snippets builds repository)
.
freeze
FEATURES
=
%i(issues merge_requests wiki snippets builds repository
pages
)
.
freeze
class
<<
self
def
access_level_attribute
(
feature
)
...
...
@@ -46,6 +48,7 @@
validates
:project
,
presence:
true
validate
:repository_children_level
validate
:allowed_access_levels
default_value_for
:builds_access_level
,
value:
ENABLED
,
allows_nil:
false
default_value_for
:issues_access_level
,
value:
ENABLED
,
allows_nil:
false
...
...
@@ -81,6 +84,16 @@
issues_access_level
>
DISABLED
end
def
pages_enabled?
pages_access_level
>
DISABLED
end
def
public_pages?
return
true
unless
Gitlab
.
config
.
pages
.
access_control
pages_access_level
==
PUBLIC
||
pages_access_level
==
ENABLED
&&
project
.
public?
end
private
# Validates builds and merge requests access level
...
...
@@ -95,6 +108,17 @@
%i(merge_requests_access_level builds_access_level)
.
each
(
&
validator
)
end
# Validates access level for other than pages cannot be PUBLIC
def
allowed_access_levels
validator
=
lambda
do
|
field
|
level
=
public_send
(
field
)
||
ProjectFeature
::
ENABLED
# rubocop:disable GitlabSecurity/PublicSend
not_allowed
=
level
>
ProjectFeature
::
ENABLED
self
.
errors
.
add
(
field
,
"cannot have public visibility level"
)
if
not_allowed
end
(
FEATURES
-
%i(pages)
).
each
{
|
f
|
validator
.
call
(
"
#{
f
}
_access_level"
)}
end
def
get_permission
(
user
,
level
)
case
level
when
DISABLED
...
...
@@ -103,6 +127,8 @@
user
&&
(
project
.
team
.
member?
(
user
)
||
user
.
full_private_access?
)
when
ENABLED
true
when
PUBLIC
true
else
true
end
...
...
app/policies/project_policy.rb
View file @
466db9af
...
...
@@ -110,6 +110,7 @@
snippets
wiki
builds
pages
]
features
.
each
do
|
f
|
...
...
@@ -167,6 +168,7 @@
enable
:upload_file
enable
:read_cycle_analytics
enable
:award_emoji
enable
:read_pages_content
end
# These abilities are not allowed to admins that are not members of the project,
...
...
@@ -286,6 +288,8 @@
prevent
(
*
create_read_update_admin_destroy
(
:merge_request
))
end
rule
{
pages_disabled
}.
prevent
:read_pages_content
rule
{
issues_disabled
&
merge_requests_disabled
}.
policy
do
prevent
(
*
create_read_update_admin_destroy
(
:label
))
prevent
(
*
create_read_update_admin_destroy
(
:milestone
))
...
...
@@ -345,6 +349,7 @@
enable
:download_code
enable
:download_wiki_code
enable
:read_cycle_analytics
enable
:read_pages_content
# NOTE: may be overridden by IssuePolicy
enable
:read_issue
...
...
app/services/projects/update_pages_configuration_service.rb
View file @
466db9af
...
...
@@ -21,7 +21,9 @@
def
pages_config
{
domains:
pages_domains_config
,
https_only:
project
.
pages_https_only?
https_only:
project
.
pages_https_only?
,
id:
project
.
project_id
,
access_control:
!
project
.
public_pages?
}
end
...
...
@@ -31,7 +33,9 @@
domain:
domain
.
domain
,
certificate:
domain
.
certificate
,
key:
domain
.
key
,
https_only:
project
.
pages_https_only?
&&
domain
.
https?
https_only:
project
.
pages_https_only?
&&
domain
.
https?
,
id:
project
.
project_id
,
access_control:
!
project
.
public_pages?
}
end
end
...
...
app/services/projects/update_service.rb
View file @
466db9af
...
...
@@ -72,7 +72,11 @@
system_hook_service
.
execute_hooks_for
(
project
,
:update
)
end
update_pages_config
if
changing_pages_https_only?
update_pages_config
if
changing_pages_related_config?
end
def
changing_pages_related_config?
changing_pages_https_only?
||
changing_pages_access_level?
end
def
update_failed!
...
...
@@ -102,6 +106,10 @@
params
.
dig
(
:project_feature_attributes
,
:wiki_access_level
).
to_i
>
ProjectFeature
::
DISABLED
end
def
changing_pages_access_level?
params
.
dig
(
:project_feature_attributes
,
:pages_access_level
)
end
def
ensure_wiki_exists
ProjectWiki
.
new
(
project
,
project
.
owner
).
wiki
rescue
ProjectWiki
::
CouldNotCreateWikiError
...
...
changelogs/unreleased/auth.yml
0 → 100644
View file @
466db9af
---
title
:
Add access control to GitLab pages and make it possible to enable/disable it in project settings
merge_request
:
18589
author
:
Tuomo Ala-Vannesluoma
type
:
added
config/gitlab.yml.example
View file @
466db9af
...
...
@@ -210,6 +210,7 @@
## GitLab Pages
pages:
enabled: false
access_control: false
# The location where pages are stored (default: shared/pages).
# path: shared/pages
...
...
config/initializers/1_settings.rb
View file @
466db9af
...
...
@@ -200,6 +200,7 @@
#
Settings
[
'pages'
]
||=
Settingslogic
.
new
({})
Settings
.
pages
[
'enabled'
]
=
false
if
Settings
.
pages
[
'enabled'
].
nil?
Settings
.
pages
[
'access_control'
]
=
false
if
Settings
.
pages
[
'access_control'
].
nil?
Settings
.
pages
[
'path'
]
=
Settings
.
absolute
(
Settings
.
pages
[
'path'
]
||
File
.
join
(
Settings
.
shared
[
'path'
],
"pages"
))
Settings
.
pages
[
'https'
]
=
false
if
Settings
.
pages
[
'https'
].
nil?
Settings
.
pages
[
'host'
]
||=
"example.com"
...
...
db/migrate/20180423204600_add_pages_access_level_to_project_feature.rb
0 → 100644
View file @
466db9af
class
AddPagesAccessLevelToProjectFeature
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
disable_ddl_transaction!
DOWNTIME
=
false
def
up
add_column_with_default
(
:project_features
,
:pages_access_level
,
:integer
,
default:
ProjectFeature
::
PUBLIC
,
allow_null:
false
)
change_column_default
(
:project_features
,
:pages_access_level
,
ProjectFeature
::
ENABLED
)
end
def
down
remove_column
:project_features
,
:pages_access_level
end
end
db/schema.rb
View file @
466db9af
...
...
@@ -1578,6 +1578,7 @@
t
.
datetime
"created_at"
t
.
datetime
"updated_at"
t
.
integer
"repository_access_level"
,
default:
20
,
null:
false
t
.
integer
"pages_access_level"
,
default:
20
,
null:
false
end
add_index
"project_features"
,
[
"project_id"
],
name:
"index_project_features_on_project_id"
,
unique:
true
,
using: :btree
...
...
doc/user/permissions.md
View file @
466db9af
...
...
@@ -110,6 +110,7 @@
-
Disabled: disabled for everyone
-
Only team members: only team members will see even if your project is public or internal
-
Everyone with access: everyone can see depending on your project visibility level
-
Everyone: enabled for everyone (only available for GitLab Pages)
### Protected branches
...
...
@@ -242,6 +243,7 @@
-
Disabled: disabled for everyone
-
Only team members: only team members will see even if your project is public or internal
-
Everyone with access: everyone can see depending on your project visibility level
-
Everyone: enabled for everyone (only available for GitLab Pages)
## GitLab CI/CD permissions
...
...
lib/api/projects.rb
View file @
466db9af
...
...
@@ -287,6 +287,12 @@
present_projects
forks
end
desc
'Check pages access of this project'
get
':id/pages_access'
do
authorize!
:read_pages_content
,
user_project
unless
user_project
.
public_pages?
status
200
end
desc
'Update an existing project'
do
success
Entities
::
Project
end
...
...
spec/factories/projects.rb
View file @
466db9af
require_relative
'../support/helpers/test_env'
FactoryBot
.
define
do
PAGES_ACCESS_LEVEL_SCHEMA_VERSION
=
20180423204600
# Project without repository
#
# Project does not have bare repository.
...
...
@@ -23,6 +25,7 @@
issues_access_level
ProjectFeature
::
ENABLED
merge_requests_access_level
ProjectFeature
::
ENABLED
repository_access_level
ProjectFeature
::
ENABLED
pages_access_level
ProjectFeature
::
ENABLED
# we can't assign the delegated `#ci_cd_settings` attributes directly, as the
# `#ci_cd_settings` relation needs to be created first
...
...
@@ -34,9 +37,9 @@
builds_access_level
=
[
evaluator
.
builds_access_level
,
evaluator
.
repository_access_level
].
min
merge_requests_access_level
=
[
evaluator
.
merge_requests_access_level
,
evaluator
.
repository_access_level
].
min
project
.
project_feature
.
update
(
hash
=
{
wiki_access_level:
evaluator
.
wiki_access_level
,
builds_access_level:
builds_access_level
,
snippets_access_level:
evaluator
.
snippets_access_level
,
issues_access_level:
evaluator
.
issues_access_level
,
merge_requests_access_level:
merge_requests_access_level
,
...
...
@@ -38,9 +41,16 @@
wiki_access_level:
evaluator
.
wiki_access_level
,
builds_access_level:
builds_access_level
,
snippets_access_level:
evaluator
.
snippets_access_level
,
issues_access_level:
evaluator
.
issues_access_level
,
merge_requests_access_level:
merge_requests_access_level
,
repository_access_level:
evaluator
.
repository_access_level
)
repository_access_level:
evaluator
.
repository_access_level
}
if
ActiveRecord
::
Migrator
.
current_version
>=
PAGES_ACCESS_LEVEL_SCHEMA_VERSION
hash
.
store
(
"pages_access_level"
,
evaluator
.
pages_access_level
)
end
project
.
project_feature
.
update
(
hash
)
# Normally the class Projects::CreateService is used for creating
# projects, and this class takes care of making sure the owner and current
...
...
@@ -244,6 +254,10 @@
trait
(
:repository_enabled
)
{
repository_access_level
ProjectFeature
::
ENABLED
}
trait
(
:repository_disabled
)
{
repository_access_level
ProjectFeature
::
DISABLED
}
trait
(
:repository_private
)
{
repository_access_level
ProjectFeature
::
PRIVATE
}
trait
(
:pages_public
)
{
pages_access_level
ProjectFeature
::
PUBLIC
}
trait
(
:pages_enabled
)
{
pages_access_level
ProjectFeature
::
ENABLED
}
trait
(
:pages_disabled
)
{
pages_access_level
ProjectFeature
::
DISABLED
}
trait
(
:pages_private
)
{
pages_access_level
ProjectFeature
::
PRIVATE
}
trait
:auto_devops
do
association
:auto_devops
,
factory: :project_auto_devops
...
...
spec/graphql/types/permission_types/project_spec.rb
View file @
466db9af
...
...
@@ -10,7 +10,7 @@
:read_commit_status
,
:request_access
,
:create_pipeline
,
:create_pipeline_schedule
,
:create_merge_request_from
,
:create_wiki
,
:push_code
,
:create_deployment
,
:push_to_delete_protected_branch
,
:admin_wiki
,
:admin_project
,
:update_pages
,
:admin_remote_mirror
,
:create_label
,
:update_wiki
,
:destroy_wiki
,
:create_pages
,
:destroy_pages
:update_wiki
,
:destroy_wiki
,
:create_pages
,
:destroy_pages
,
:read_pages_content
]
expect
(
described_class
).
to
have_graphql_fields
(
expected_permissions
)
...
...
spec/lib/gitlab/import_export/safe_model_attributes.yml
View file @
466db9af
...
...
@@ -492,6 +492,7 @@
-
snippets_access_level
-
builds_access_level
-
repository_access_level
-
pages_access_level
-
created_at
-
updated_at
ProtectedBranch::MergeAccessLevel:
...
...
Prev
1
2
Next
Write
Preview
Supports
Markdown
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