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
0
Merge Requests
0
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
Boxiang Sun
gitlab-ce
Commits
9d45951f
Commit
9d45951f
authored
Jan 03, 2018
by
Rob Watson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add HTTPS-only pages
Closes #28857
parent
53d352aa
Changes
24
Hide whitespace changes
Inline
Side-by-side
Showing
24 changed files
with
447 additions
and
107 deletions
+447
-107
app/controllers/projects/pages_controller.rb
app/controllers/projects/pages_controller.rb
+22
-0
app/helpers/projects_helper.rb
app/helpers/projects_helper.rb
+18
-0
app/models/pages_domain.rb
app/models/pages_domain.rb
+8
-2
app/models/project.rb
app/models/project.rb
+21
-0
app/services/projects/update_pages_configuration_service.rb
app/services/projects/update_pages_configuration_service.rb
+4
-2
app/services/projects/update_service.rb
app/services/projects/update_service.rb
+10
-0
app/validators/certificate_validator.rb
app/validators/certificate_validator.rb
+0
-2
app/views/projects/pages/_https_only.html.haml
app/views/projects/pages/_https_only.html.haml
+10
-0
app/views/projects/pages/show.html.haml
app/views/projects/pages/show.html.haml
+3
-0
changelogs/unreleased/pages_force_https.yml
changelogs/unreleased/pages_force_https.yml
+5
-0
config/routes/project.rb
config/routes/project.rb
+1
-1
db/migrate/20180102220145_add_pages_https_only_to_projects.rb
...igrate/20180102220145_add_pages_https_only_to_projects.rb
+9
-0
db/migrate/20180109183319_change_default_value_for_pages_https_only.rb
...180109183319_change_default_value_for_pages_https_only.rb
+13
-0
db/schema.rb
db/schema.rb
+1
-0
spec/controllers/projects/pages_controller_spec.rb
spec/controllers/projects/pages_controller_spec.rb
+37
-0
spec/controllers/projects/pages_domains_controller_spec.rb
spec/controllers/projects/pages_domains_controller_spec.rb
+2
-2
spec/factories/pages_domains.rb
spec/factories/pages_domains.rb
+26
-22
spec/features/projects/pages_spec.rb
spec/features/projects/pages_spec.rb
+70
-20
spec/lib/gitlab/import_export/safe_model_attributes.yml
spec/lib/gitlab/import_export/safe_model_attributes.yml
+1
-0
spec/models/pages_domain_spec.rb
spec/models/pages_domain_spec.rb
+97
-49
spec/models/project_spec.rb
spec/models/project_spec.rb
+45
-0
spec/requests/api/pages_domains_spec.rb
spec/requests/api/pages_domains_spec.rb
+7
-7
spec/services/projects/update_service_spec.rb
spec/services/projects/update_service_spec.rb
+21
-0
spec/spec_helper.rb
spec/spec_helper.rb
+16
-0
No files found.
app/controllers/projects/pages_controller.rb
View file @
9d45951f
...
@@ -21,4 +21,26 @@ class Projects::PagesController < Projects::ApplicationController
...
@@ -21,4 +21,26 @@ class Projects::PagesController < Projects::ApplicationController
end
end
end
end
end
end
def
update
result
=
Projects
::
UpdateService
.
new
(
@project
,
current_user
,
project_params
).
execute
respond_to
do
|
format
|
format
.
html
do
if
result
[
:status
]
==
:success
flash
[
:notice
]
=
'Your changes have been saved'
else
flash
[
:alert
]
=
'Something went wrong on our end'
end
redirect_to
project_pages_path
(
@project
)
end
end
end
private
def
project_params
params
.
require
(
:project
).
permit
(
:pages_https_only
)
end
end
end
app/helpers/projects_helper.rb
View file @
9d45951f
...
@@ -531,4 +531,22 @@ module ProjectsHelper
...
@@ -531,4 +531,22 @@ module ProjectsHelper
def
can_show_last_commit_in_list?
(
project
)
def
can_show_last_commit_in_list?
(
project
)
can?
(
current_user
,
:read_cross_project
)
&&
project
.
commit
can?
(
current_user
,
:read_cross_project
)
&&
project
.
commit
end
end
def
pages_https_only_disabled?
!
@project
.
pages_domains
.
all?
(
&
:https?
)
end
def
pages_https_only_title
return
unless
pages_https_only_disabled?
"You must enable HTTPS for all your domains first"
end
def
pages_https_only_label_class
if
pages_https_only_disabled?
"list-label disabled"
else
"list-label"
end
end
end
end
app/models/pages_domain.rb
View file @
9d45951f
...
@@ -6,8 +6,10 @@ class PagesDomain < ActiveRecord::Base
...
@@ -6,8 +6,10 @@ class PagesDomain < ActiveRecord::Base
validates
:domain
,
hostname:
{
allow_numeric_hostname:
true
}
validates
:domain
,
hostname:
{
allow_numeric_hostname:
true
}
validates
:domain
,
uniqueness:
{
case_sensitive:
false
}
validates
:domain
,
uniqueness:
{
case_sensitive:
false
}
validates
:certificate
,
certificate:
true
,
allow_nil:
true
,
allow_blank:
true
validates
:certificate
,
presence:
{
message:
'must be present if HTTPS-only is enabled'
},
if:
->
(
domain
)
{
domain
.
project
&
.
pages_https_only?
}
validates
:key
,
certificate_key:
true
,
allow_nil:
true
,
allow_blank:
true
validates
:certificate
,
certificate:
true
,
if:
->
(
domain
)
{
domain
.
certificate
.
present?
}
validates
:key
,
presence:
{
message:
'must be present if HTTPS-only is enabled'
},
if:
->
(
domain
)
{
domain
.
project
&
.
pages_https_only?
}
validates
:key
,
certificate_key:
true
,
if:
->
(
domain
)
{
domain
.
key
.
present?
}
validates
:verification_code
,
presence:
true
,
allow_blank:
false
validates
:verification_code
,
presence:
true
,
allow_blank:
false
validate
:validate_pages_domain
validate
:validate_pages_domain
...
@@ -46,6 +48,10 @@ class PagesDomain < ActiveRecord::Base
...
@@ -46,6 +48,10 @@ class PagesDomain < ActiveRecord::Base
!
Gitlab
::
CurrentSettings
.
pages_domain_verification_enabled?
||
enabled_until
.
present?
!
Gitlab
::
CurrentSettings
.
pages_domain_verification_enabled?
||
enabled_until
.
present?
end
end
def
https?
certificate
.
present?
end
def
to_param
def
to_param
domain
domain
end
end
...
...
app/models/project.rb
View file @
9d45951f
...
@@ -267,6 +267,7 @@ class Project < ActiveRecord::Base
...
@@ -267,6 +267,7 @@ class Project < ActiveRecord::Base
validate
:visibility_level_allowed_by_group
validate
:visibility_level_allowed_by_group
validate
:visibility_level_allowed_as_fork
validate
:visibility_level_allowed_as_fork
validate
:check_wiki_path_conflict
validate
:check_wiki_path_conflict
validate
:validate_pages_https_only
,
if:
->
{
changes
.
has_key?
(
:pages_https_only
)
}
validates
:repository_storage
,
validates
:repository_storage
,
presence:
true
,
presence:
true
,
inclusion:
{
in:
->
(
_object
)
{
Gitlab
.
config
.
repositories
.
storages
.
keys
}
}
inclusion:
{
in:
->
(
_object
)
{
Gitlab
.
config
.
repositories
.
storages
.
keys
}
}
...
@@ -737,6 +738,26 @@ class Project < ActiveRecord::Base
...
@@ -737,6 +738,26 @@ class Project < ActiveRecord::Base
end
end
end
end
def
pages_https_only
return
false
unless
Gitlab
.
config
.
pages
.
external_https
super
end
def
pages_https_only?
return
false
unless
Gitlab
.
config
.
pages
.
external_https
super
end
def
validate_pages_https_only
return
unless
pages_https_only?
unless
pages_domains
.
all?
(
&
:https?
)
errors
.
add
(
:pages_https_only
,
"cannot be enabled unless all domains have TLS certificates"
)
end
end
def
to_param
def
to_param
if
persisted?
&&
errors
.
include?
(
:path
)
if
persisted?
&&
errors
.
include?
(
:path
)
path_was
path_was
...
...
app/services/projects/update_pages_configuration_service.rb
View file @
9d45951f
...
@@ -18,7 +18,8 @@ module Projects
...
@@ -18,7 +18,8 @@ module Projects
def
pages_config
def
pages_config
{
{
domains:
pages_domains_config
domains:
pages_domains_config
,
https_only:
project
.
pages_https_only?
}
}
end
end
...
@@ -27,7 +28,8 @@ module Projects
...
@@ -27,7 +28,8 @@ module Projects
{
{
domain:
domain
.
domain
,
domain:
domain
.
domain
,
certificate:
domain
.
certificate
,
certificate:
domain
.
certificate
,
key:
domain
.
key
key:
domain
.
key
,
https_only:
project
.
pages_https_only?
&&
domain
.
https?
}
}
end
end
end
end
...
...
app/services/projects/update_service.rb
View file @
9d45951f
...
@@ -24,6 +24,8 @@ module Projects
...
@@ -24,6 +24,8 @@ module Projects
system_hook_service
.
execute_hooks_for
(
project
,
:update
)
system_hook_service
.
execute_hooks_for
(
project
,
:update
)
end
end
update_pages_config
if
changing_pages_https_only?
success
success
else
else
model_errors
=
project
.
errors
.
full_messages
.
to_sentence
model_errors
=
project
.
errors
.
full_messages
.
to_sentence
...
@@ -67,5 +69,13 @@ module Projects
...
@@ -67,5 +69,13 @@ module Projects
log_error
(
"Could not create wiki for
#{
project
.
full_name
}
"
)
log_error
(
"Could not create wiki for
#{
project
.
full_name
}
"
)
Gitlab
::
Metrics
.
counter
(
:wiki_can_not_be_created_total
,
'Counts the times we failed to create a wiki'
)
Gitlab
::
Metrics
.
counter
(
:wiki_can_not_be_created_total
,
'Counts the times we failed to create a wiki'
)
end
end
def
update_pages_config
Projects
::
UpdatePagesConfigurationService
.
new
(
project
).
execute
end
def
changing_pages_https_only?
project
.
previous_changes
.
include?
(
:pages_https_only
)
end
end
end
end
end
app/validators/certificate_validator.rb
View file @
9d45951f
...
@@ -16,8 +16,6 @@ class CertificateValidator < ActiveModel::EachValidator
...
@@ -16,8 +16,6 @@ class CertificateValidator < ActiveModel::EachValidator
private
private
def
valid_certificate_pem?
(
value
)
def
valid_certificate_pem?
(
value
)
return
false
unless
value
OpenSSL
::
X509
::
Certificate
.
new
(
value
).
present?
OpenSSL
::
X509
::
Certificate
.
new
(
value
).
present?
rescue
OpenSSL
::
X509
::
CertificateError
rescue
OpenSSL
::
X509
::
CertificateError
false
false
...
...
app/views/projects/pages/_https_only.html.haml
0 → 100644
View file @
9d45951f
=
form_for
@project
,
url:
namespace_project_pages_path
(
@project
.
namespace
.
becomes
(
Namespace
),
@project
),
html:
{
class:
'inline'
,
title:
pages_https_only_title
}
do
|
f
|
=
f
.
check_box
:pages_https_only
,
class:
'pull-left'
,
disabled:
pages_https_only_disabled?
.prepend-left-20
=
f
.
label
:pages_https_only
,
class:
pages_https_only_label_class
do
%strong
Force domains with SSL certificates to use HTTPS
-
unless
pages_https_only_disabled?
.prepend-top-10
=
f
.
submit
'Save'
,
class:
'btn btn-success'
app/views/projects/pages/show.html.haml
View file @
9d45951f
...
@@ -13,6 +13,9 @@
...
@@ -13,6 +13,9 @@
Combined with the power of GitLab CI and the help of GitLab Runner
Combined with the power of GitLab CI and the help of GitLab Runner
you can deploy static pages for your individual projects, your user or your group.
you can deploy static pages for your individual projects, your user or your group.
-
if
Gitlab
.
config
.
pages
.
external_https
=
render
'https_only'
%hr
.clearfix
%hr
.clearfix
=
render
'access'
=
render
'access'
...
...
changelogs/unreleased/pages_force_https.yml
0 → 100644
View file @
9d45951f
---
title
:
Add HTTPS-only pages
merge_request
:
16273
author
:
rfwatson
type
:
added
config/routes/project.rb
View file @
9d45951f
...
@@ -52,7 +52,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
...
@@ -52,7 +52,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
end
end
end
end
resource
:pages
,
only:
[
:show
,
:destroy
]
do
resource
:pages
,
only:
[
:show
,
:
update
,
:
destroy
]
do
resources
:domains
,
except: :index
,
controller:
'pages_domains'
,
constraints:
{
id:
%r{[^/]+}
}
do
resources
:domains
,
except: :index
,
controller:
'pages_domains'
,
constraints:
{
id:
%r{[^/]+}
}
do
member
do
member
do
post
:verify
post
:verify
...
...
db/migrate/20180102220145_add_pages_https_only_to_projects.rb
0 → 100644
View file @
9d45951f
class
AddPagesHttpsOnlyToProjects
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
def
change
add_column
:projects
,
:pages_https_only
,
:boolean
end
end
db/migrate/20180109183319_change_default_value_for_pages_https_only.rb
0 → 100644
View file @
9d45951f
class
ChangeDefaultValueForPagesHttpsOnly
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
def
up
change_column_default
:projects
,
:pages_https_only
,
true
end
def
down
change_column_default
:projects
,
:pages_https_only
,
nil
end
end
db/schema.rb
View file @
9d45951f
...
@@ -1513,6 +1513,7 @@ ActiveRecord::Schema.define(version: 20180320182229) do
...
@@ -1513,6 +1513,7 @@ ActiveRecord::Schema.define(version: 20180320182229) do
t
.
boolean
"merge_requests_ff_only_enabled"
,
default:
false
t
.
boolean
"merge_requests_ff_only_enabled"
,
default:
false
t
.
boolean
"merge_requests_rebase_enabled"
,
default:
false
,
null:
false
t
.
boolean
"merge_requests_rebase_enabled"
,
default:
false
,
null:
false
t
.
integer
"jobs_cache_index"
t
.
integer
"jobs_cache_index"
t
.
boolean
"pages_https_only"
,
default:
true
end
end
add_index
"projects"
,
[
"ci_id"
],
name:
"index_projects_on_ci_id"
,
using: :btree
add_index
"projects"
,
[
"ci_id"
],
name:
"index_projects_on_ci_id"
,
using: :btree
...
...
spec/controllers/projects/pages_controller_spec.rb
View file @
9d45951f
...
@@ -65,4 +65,41 @@ describe Projects::PagesController do
...
@@ -65,4 +65,41 @@ describe Projects::PagesController do
end
end
end
end
end
end
describe
'PATCH update'
do
let
(
:request_params
)
do
{
namespace_id:
project
.
namespace
,
project_id:
project
,
project:
{
pages_https_only:
false
}
}
end
let
(
:update_service
)
{
double
(
execute:
{
status: :success
})
}
before
do
allow
(
Projects
::
UpdateService
).
to
receive
(
:new
)
{
update_service
}
end
it
'returns 302 status'
do
patch
:update
,
request_params
expect
(
response
).
to
have_gitlab_http_status
(
:found
)
end
it
'redirects back to the pages settings'
do
patch
:update
,
request_params
expect
(
response
).
to
redirect_to
(
project_pages_path
(
project
))
end
it
'calls the update service'
do
expect
(
Projects
::
UpdateService
)
.
to
receive
(
:new
)
.
with
(
project
,
user
,
request_params
[
:project
])
.
and_return
(
update_service
)
patch
:update
,
request_params
end
end
end
end
spec/controllers/projects/pages_domains_controller_spec.rb
View file @
9d45951f
...
@@ -13,7 +13,7 @@ describe Projects::PagesDomainsController do
...
@@ -13,7 +13,7 @@ describe Projects::PagesDomainsController do
end
end
let
(
:pages_domain_params
)
do
let
(
:pages_domain_params
)
do
build
(
:pages_domain
,
:with_certificate
,
:with_key
,
domain:
'my.otherdomain.com'
).
slice
(
:key
,
:certificate
,
:domain
)
build
(
:pages_domain
,
domain:
'my.otherdomain.com'
).
slice
(
:key
,
:certificate
,
:domain
)
end
end
before
do
before
do
...
@@ -68,7 +68,7 @@ describe Projects::PagesDomainsController do
...
@@ -68,7 +68,7 @@ describe Projects::PagesDomainsController do
end
end
let
(
:pages_domain_params
)
do
let
(
:pages_domain_params
)
do
attributes_for
(
:pages_domain
,
:with_certificate
,
:with_key
).
slice
(
:key
,
:certificate
)
attributes_for
(
:pages_domain
).
slice
(
:key
,
:certificate
)
end
end
let
(
:params
)
do
let
(
:params
)
do
...
...
spec/factories/pages_domains.rb
View file @
9d45951f
...
@@ -4,25 +4,7 @@ FactoryBot.define do
...
@@ -4,25 +4,7 @@ FactoryBot.define do
verified_at
{
Time
.
now
}
verified_at
{
Time
.
now
}
enabled_until
{
1
.
week
.
from_now
}
enabled_until
{
1
.
week
.
from_now
}
trait
:disabled
do
certificate
'-----BEGIN CERTIFICATE-----
verified_at
nil
enabled_until
nil
end
trait
:unverified
do
verified_at
nil
end
trait
:reverify
do
enabled_until
{
1
.
hour
.
from_now
}
end
trait
:expired
do
enabled_until
{
1
.
hour
.
ago
}
end
trait
:with_certificate
do
certificate
'-----BEGIN CERTIFICATE-----
MIICGzCCAYSgAwIBAgIBATANBgkqhkiG9w0BAQUFADAbMRkwFwYDVQQDExB0ZXN0
MIICGzCCAYSgAwIBAgIBATANBgkqhkiG9w0BAQUFADAbMRkwFwYDVQQDExB0ZXN0
LWNlcnRpZmljYXRlMB4XDTE2MDIxMjE0MzIwMFoXDTIwMDQxMjE0MzIwMFowGzEZ
LWNlcnRpZmljYXRlMB4XDTE2MDIxMjE0MzIwMFoXDTIwMDQxMjE0MzIwMFowGzEZ
MBcGA1UEAxMQdGVzdC1jZXJ0aWZpY2F0ZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
MBcGA1UEAxMQdGVzdC1jZXJ0aWZpY2F0ZTCBnzANBgkqhkiG9w0BAQEFAAOBjQAw
...
@@ -36,10 +18,8 @@ joZp2JHYvNlTPkRJ/J4TcXxBTJmArcQgTIuNoBtC+0A/SwdK4MfTCUY4vNWNdese
...
@@ -36,10 +18,8 @@ joZp2JHYvNlTPkRJ/J4TcXxBTJmArcQgTIuNoBtC+0A/SwdK4MfTCUY4vNWNdese
5A4K65Nb7Oh1AdQieTBHNXXCdyFsva9/ScfQGEl7p55a52jOPs0StPd7g64uvjlg
5A4K65Nb7Oh1AdQieTBHNXXCdyFsva9/ScfQGEl7p55a52jOPs0StPd7g64uvjlg
YHi2yesCrOvVXt+lgPTd
YHi2yesCrOvVXt+lgPTd
-----END CERTIFICATE-----'
-----END CERTIFICATE-----'
end
trait
:with_key
do
key
'-----BEGIN PRIVATE KEY-----
key
'-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKS+CfS9GcRSdYSN
MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAKS+CfS9GcRSdYSN
SzyH5QJQBr5umRL6E+KilOV39iYFO/9oHjUdapTRWkrwnNPCp7qaeck4Jr8iv14t
SzyH5QJQBr5umRL6E+KilOV39iYFO/9oHjUdapTRWkrwnNPCp7qaeck4Jr8iv14t
PVNDfNr76eGb6/3YknOAP0QOjLWunoC8kjU+N/JHU52NrUeX3qEy8EKV9LeCDJcB
PVNDfNr76eGb6/3YknOAP0QOjLWunoC8kjU+N/JHU52NrUeX3qEy8EKV9LeCDJcB
...
@@ -55,6 +35,30 @@ EPjGlXIT+aW2XiPmK3ZlCDcWIenE+lmtbOpI159Wpk8BGXs/s/xBAkEAlAY3ymgx
...
@@ -55,6 +35,30 @@ EPjGlXIT+aW2XiPmK3ZlCDcWIenE+lmtbOpI159Wpk8BGXs/s/xBAkEAlAY3ymgx
63BDJEwvOb2IaP8lDDxNsXx9XJNVvQbv5n15vNsLHbjslHfAhAbxnLQ1fLhUPqSi
63BDJEwvOb2IaP8lDDxNsXx9XJNVvQbv5n15vNsLHbjslHfAhAbxnLQ1fLhUPqSi
nNp/xedE1YxutQ==
nNp/xedE1YxutQ==
-----END PRIVATE KEY-----'
-----END PRIVATE KEY-----'
trait
:disabled
do
verified_at
nil
enabled_until
nil
end
trait
:unverified
do
verified_at
nil
end
trait
:reverify
do
enabled_until
{
1
.
hour
.
from_now
}
end
trait
:expired
do
enabled_until
{
1
.
hour
.
ago
}
end
trait
:without_certificate
do
certificate
nil
end
trait
:without_key
do
key
nil
end
end
trait
:with_missing_chain
do
trait
:with_missing_chain
do
...
...
spec/features/projects/pages_spec.rb
View file @
9d45951f
...
@@ -40,11 +40,6 @@ feature 'Pages' do
...
@@ -40,11 +40,6 @@ feature 'Pages' do
end
end
context
'when support for external domains is disabled'
do
context
'when support for external domains is disabled'
do
before
do
allow
(
Gitlab
.
config
.
pages
).
to
receive
(
:external_http
).
and_return
(
nil
)
allow
(
Gitlab
.
config
.
pages
).
to
receive
(
:external_https
).
and_return
(
nil
)
end
it
'renders message that support is disabled'
do
it
'renders message that support is disabled'
do
visit
project_pages_path
(
project
)
visit
project_pages_path
(
project
)
...
@@ -52,7 +47,9 @@ feature 'Pages' do
...
@@ -52,7 +47,9 @@ feature 'Pages' do
end
end
end
end
context
'when pages are exposed on external HTTP address'
do
context
'when pages are exposed on external HTTP address'
,
:http_pages_enabled
do
given
(
:project
)
{
create
(
:project
,
pages_https_only:
false
)
}
shared_examples
'adds new domain'
do
shared_examples
'adds new domain'
do
it
'adds new domain'
do
it
'adds new domain'
do
visit
new_project_pages_domain_path
(
project
)
visit
new_project_pages_domain_path
(
project
)
...
@@ -64,11 +61,6 @@ feature 'Pages' do
...
@@ -64,11 +61,6 @@ feature 'Pages' do
end
end
end
end
before
do
allow
(
Gitlab
.
config
.
pages
).
to
receive
(
:external_http
).
and_return
([
'1.1.1.1:80'
])
allow
(
Gitlab
.
config
.
pages
).
to
receive
(
:external_https
).
and_return
(
nil
)
end
it
'allows to add new domain'
do
it
'allows to add new domain'
do
visit
project_pages_path
(
project
)
visit
project_pages_path
(
project
)
...
@@ -80,13 +72,13 @@ feature 'Pages' do
...
@@ -80,13 +72,13 @@ feature 'Pages' do
context
'when project in group namespace'
do
context
'when project in group namespace'
do
it_behaves_like
'adds new domain'
do
it_behaves_like
'adds new domain'
do
let
(
:group
)
{
create
:group
}
let
(
:group
)
{
create
:group
}
let
(
:project
)
{
create
:project
,
namespace:
group
}
let
(
:project
)
{
create
(
:project
,
namespace:
group
,
pages_https_only:
false
)
}
end
end
end
end
context
'when pages domain is added'
do
context
'when pages domain is added'
do
before
do
before
do
project
.
pages_domains
.
create!
(
domain:
'my.test.domain.com'
)
create
(
:pages_domain
,
project:
project
,
domain:
'my.test.domain.com'
)
visit
new_project_pages_domain_path
(
project
)
visit
new_project_pages_domain_path
(
project
)
end
end
...
@@ -104,7 +96,7 @@ feature 'Pages' do
...
@@ -104,7 +96,7 @@ feature 'Pages' do
end
end
end
end
context
'when pages are exposed on external HTTPS address'
do
context
'when pages are exposed on external HTTPS address'
,
:https_pages_enabled
do
let
(
:certificate_pem
)
do
let
(
:certificate_pem
)
do
<<~
PEM
<<~
PEM
-----BEGIN CERTIFICATE-----
-----BEGIN CERTIFICATE-----
...
@@ -145,11 +137,6 @@ feature 'Pages' do
...
@@ -145,11 +137,6 @@ feature 'Pages' do
KEY
KEY
end
end
before
do
allow
(
Gitlab
.
config
.
pages
).
to
receive
(
:external_http
).
and_return
([
'1.1.1.1:80'
])
allow
(
Gitlab
.
config
.
pages
).
to
receive
(
:external_https
).
and_return
([
'1.1.1.1:443'
])
end
it
'adds new domain with certificate'
do
it
'adds new domain with certificate'
do
visit
new_project_pages_domain_path
(
project
)
visit
new_project_pages_domain_path
(
project
)
...
@@ -163,7 +150,7 @@ feature 'Pages' do
...
@@ -163,7 +150,7 @@ feature 'Pages' do
describe
'updating the certificate for an existing domain'
do
describe
'updating the certificate for an existing domain'
do
let!
(
:domain
)
do
let!
(
:domain
)
do
create
(
:pages_domain
,
:with_key
,
:with_certificate
,
project:
project
)
create
(
:pages_domain
,
project:
project
)
end
end
it
'allows the certificate to be updated'
do
it
'allows the certificate to be updated'
do
...
@@ -237,6 +224,69 @@ feature 'Pages' do
...
@@ -237,6 +224,69 @@ feature 'Pages' do
it_behaves_like
'no pages deployed'
it_behaves_like
'no pages deployed'
end
end
describe
'HTTPS settings'
,
:js
,
:https_pages_enabled
do
background
do
project
.
namespace
.
update
(
owner:
user
)
allow_any_instance_of
(
Project
).
to
receive
(
:pages_deployed?
)
{
true
}
end
scenario
'tries to change the setting'
do
visit
project_pages_path
(
project
)
expect
(
page
).
to
have_content
(
"Force domains with SSL certificates to use HTTPS"
)
uncheck
:project_pages_https_only
click_button
'Save'
expect
(
page
).
to
have_text
(
'Your changes have been saved'
)
expect
(
page
).
not_to
have_checked_field
(
'project_pages_https_only'
)
end
context
'setting could not be updated'
do
before
do
allow_any_instance_of
(
Projects
::
UpdateService
)
.
to
receive
(
:execute
)
.
and_return
(
status: :error
)
end
scenario
'tries to change the setting'
do
visit
project_pages_path
(
project
)
uncheck
:project_pages_https_only
click_button
'Save'
expect
(
page
).
to
have_text
(
'Something went wrong on our end'
)
end
end
context
'non-HTTPS domain exists'
do
given
(
:project
)
{
create
(
:project
,
pages_https_only:
false
)
}
before
do
create
(
:pages_domain
,
:without_key
,
:without_certificate
,
project:
project
)
end
scenario
'the setting is disabled'
do
visit
project_pages_path
(
project
)
expect
(
page
).
to
have_field
(
:project_pages_https_only
,
disabled:
true
)
expect
(
page
).
not_to
have_button
(
'Save'
)
end
end
context
'HTTPS pages are disabled'
,
:https_pages_disabled
do
scenario
'the setting is unavailable'
do
visit
project_pages_path
(
project
)
expect
(
page
).
not_to
have_field
(
:project_pages_https_only
)
expect
(
page
).
not_to
have_content
(
'Force domains with SSL certificates to use HTTPS'
)
expect
(
page
).
not_to
have_button
(
'Save'
)
end
end
end
describe
'Remove page'
do
describe
'Remove page'
do
context
'when user is the owner'
do
context
'when user is the owner'
do
let
(
:project
)
{
create
:project
,
:repository
}
let
(
:project
)
{
create
:project
,
:repository
}
...
...
spec/lib/gitlab/import_export/safe_model_attributes.yml
View file @
9d45951f
...
@@ -458,6 +458,7 @@ Project:
...
@@ -458,6 +458,7 @@ Project:
-
merge_requests_ff_only_enabled
-
merge_requests_ff_only_enabled
-
merge_requests_rebase_enabled
-
merge_requests_rebase_enabled
-
jobs_cache_index
-
jobs_cache_index
-
pages_https_only
Author
:
Author
:
-
name
-
name
ProjectFeature
:
ProjectFeature
:
...
...
spec/models/pages_domain_spec.rb
View file @
9d45951f
...
@@ -18,24 +18,63 @@ describe PagesDomain do
...
@@ -18,24 +18,63 @@ describe PagesDomain do
it
{
is_expected
.
to
validate_uniqueness_of
(
:domain
).
case_insensitive
}
it
{
is_expected
.
to
validate_uniqueness_of
(
:domain
).
case_insensitive
}
end
end
{
describe
"hostname"
do
'my.domain.com'
=>
true
,
{
'123.456.789'
=>
true
,
'my.domain.com'
=>
true
,
'0x12345.com'
=>
true
,
'123.456.789'
=>
true
,
'0123123'
=>
true
,
'0x12345.com'
=>
true
,
'_foo.com'
=>
false
,
'0123123'
=>
true
,
'reserved.com'
=>
false
,
'_foo.com'
=>
false
,
'a.reserved.com'
=>
false
,
'reserved.com'
=>
false
,
nil
=>
false
'a.reserved.com'
=>
false
,
}.
each
do
|
value
,
validity
|
nil
=>
false
context
"domain
#{
value
.
inspect
}
validity"
do
}.
each
do
|
value
,
validity
|
before
do
context
"domain
#{
value
.
inspect
}
validity"
do
allow
(
Settings
.
pages
).
to
receive
(
:host
).
and_return
(
'reserved.com'
)
before
do
allow
(
Settings
.
pages
).
to
receive
(
:host
).
and_return
(
'reserved.com'
)
end
let
(
:domain
)
{
value
}
it
{
expect
(
pages_domain
.
valid?
).
to
eq
(
validity
)
}
end
end
end
describe
"HTTPS-only"
do
using
RSpec
::
Parameterized
::
TableSyntax
let
(
:domain
)
{
'my.domain.com'
}
let
(
:project
)
do
instance_double
(
Project
,
pages_https_only?:
pages_https_only
)
end
let
(
:pages_domain
)
do
build
(
:pages_domain
,
certificate:
certificate
,
key:
key
).
tap
do
|
pd
|
allow
(
pd
).
to
receive
(
:project
).
and_return
(
project
)
pd
.
valid?
end
end
end
let
(
:domain
)
{
value
}
where
(
:pages_https_only
,
:certificate
,
:key
,
:errors_on
)
do
attributes
=
attributes_for
(
:pages_domain
)
cert
,
key
=
attributes
.
fetch_values
(
:certificate
,
:key
)
true
|
nil
|
nil
|
%i(certificate key)
true
|
cert
|
nil
|
%i(key)
true
|
nil
|
key
|
%i(certificate key)
true
|
cert
|
key
|
[]
false
|
nil
|
nil
|
[]
false
|
cert
|
nil
|
%i(key)
false
|
nil
|
key
|
%i(key)
false
|
cert
|
key
|
[]
end
it
{
expect
(
pages_domain
.
valid?
).
to
eq
(
validity
)
}
with_them
do
it
"is adds the expected errors"
do
expect
(
pages_domain
.
errors
.
keys
).
to
eq
errors_on
end
end
end
end
end
end
end
...
@@ -43,26 +82,26 @@ describe PagesDomain do
...
@@ -43,26 +82,26 @@ describe PagesDomain do
describe
'validate certificate'
do
describe
'validate certificate'
do
subject
{
domain
}
subject
{
domain
}
context
'w
hen only certificate is specified
'
do
context
'w
ith matching key
'
do
let
(
:domain
)
{
build
(
:pages_domain
,
:with_certificate
)
}
let
(
:domain
)
{
build
(
:pages_domain
)
}
it
{
is_expected
.
not_
to
be_valid
}
it
{
is_expected
.
to
be_valid
}
end
end
context
'when
only key
is specified'
do
context
'when
no certificate
is specified'
do
let
(
:domain
)
{
build
(
:pages_domain
,
:with
_key
)
}
let
(
:domain
)
{
build
(
:pages_domain
,
:with
out_certificate
)
}
it
{
is_expected
.
not_to
be_valid
}
it
{
is_expected
.
not_to
be_valid
}
end
end
context
'w
ith matching key
'
do
context
'w
hen no key is specified
'
do
let
(
:domain
)
{
build
(
:pages_domain
,
:with
_certificate
,
:with
_key
)
}
let
(
:domain
)
{
build
(
:pages_domain
,
:with
out
_key
)
}
it
{
is_expected
.
to
be_valid
}
it
{
is_expected
.
not_
to
be_valid
}
end
end
context
'for not matching key'
do
context
'for not matching key'
do
let
(
:domain
)
{
build
(
:pages_domain
,
:with_missing_chain
,
:with_key
)
}
let
(
:domain
)
{
build
(
:pages_domain
,
:with_missing_chain
)
}
it
{
is_expected
.
not_to
be_valid
}
it
{
is_expected
.
not_to
be_valid
}
end
end
...
@@ -103,30 +142,26 @@ describe PagesDomain do
...
@@ -103,30 +142,26 @@ describe PagesDomain do
describe
'#url'
do
describe
'#url'
do
subject
{
domain
.
url
}
subject
{
domain
.
url
}
context
'without the certificate'
do
let
(
:domain
)
{
build
(
:pages_domain
)
}
let
(
:domain
)
{
build
(
:pages_domain
,
certificate:
''
)
}
it
{
is_expected
.
to
eq
(
"http://
#{
domain
.
domain
}
"
)
}
it
{
is_expected
.
to
eq
(
"https://
#{
domain
.
domain
}
"
)
}
end
context
'with
a
certificate'
do
context
'with
out the
certificate'
do
let
(
:domain
)
{
build
(
:pages_domain
,
:with_certificate
)
}
let
(
:domain
)
{
build
(
:pages_domain
,
:with
out
_certificate
)
}
it
{
is_expected
.
to
eq
(
"http
s
://
#{
domain
.
domain
}
"
)
}
it
{
is_expected
.
to
eq
(
"http://
#{
domain
.
domain
}
"
)
}
end
end
end
end
describe
'#has_matching_key?'
do
describe
'#has_matching_key?'
do
subject
{
domain
.
has_matching_key?
}
subject
{
domain
.
has_matching_key?
}
context
'for matching key'
do
let
(
:domain
)
{
build
(
:pages_domain
)
}
let
(
:domain
)
{
build
(
:pages_domain
,
:with_certificate
,
:with_key
)
}
it
{
is_expected
.
to
be_truthy
}
it
{
is_expected
.
to
be_truthy
}
end
context
'for invalid key'
do
context
'for invalid key'
do
let
(
:domain
)
{
build
(
:pages_domain
,
:with_missing_chain
,
:with_key
)
}
let
(
:domain
)
{
build
(
:pages_domain
,
:with_missing_chain
)
}
it
{
is_expected
.
to
be_falsey
}
it
{
is_expected
.
to
be_falsey
}
end
end
...
@@ -136,7 +171,7 @@ describe PagesDomain do
...
@@ -136,7 +171,7 @@ describe PagesDomain do
subject
{
domain
.
has_intermediates?
}
subject
{
domain
.
has_intermediates?
}
context
'for self signed'
do
context
'for self signed'
do
let
(
:domain
)
{
build
(
:pages_domain
,
:with_certificate
)
}
let
(
:domain
)
{
build
(
:pages_domain
)
}
it
{
is_expected
.
to
be_truthy
}
it
{
is_expected
.
to
be_truthy
}
end
end
...
@@ -162,7 +197,7 @@ describe PagesDomain do
...
@@ -162,7 +197,7 @@ describe PagesDomain do
subject
{
domain
.
expired?
}
subject
{
domain
.
expired?
}
context
'for valid'
do
context
'for valid'
do
let
(
:domain
)
{
build
(
:pages_domain
,
:with_certificate
)
}
let
(
:domain
)
{
build
(
:pages_domain
)
}
it
{
is_expected
.
to
be_falsey
}
it
{
is_expected
.
to
be_falsey
}
end
end
...
@@ -175,7 +210,7 @@ describe PagesDomain do
...
@@ -175,7 +210,7 @@ describe PagesDomain do
end
end
describe
'#subject'
do
describe
'#subject'
do
let
(
:domain
)
{
build
(
:pages_domain
,
:with_certificate
)
}
let
(
:domain
)
{
build
(
:pages_domain
)
}
subject
{
domain
.
subject
}
subject
{
domain
.
subject
}
...
@@ -183,7 +218,7 @@ describe PagesDomain do
...
@@ -183,7 +218,7 @@ describe PagesDomain do
end
end
describe
'#certificate_text'
do
describe
'#certificate_text'
do
let
(
:domain
)
{
build
(
:pages_domain
,
:with_certificate
)
}
let
(
:domain
)
{
build
(
:pages_domain
)
}
subject
{
domain
.
certificate_text
}
subject
{
domain
.
certificate_text
}
...
@@ -191,6 +226,18 @@ describe PagesDomain do
...
@@ -191,6 +226,18 @@ describe PagesDomain do
it
{
is_expected
.
not_to
be_empty
}
it
{
is_expected
.
not_to
be_empty
}
end
end
describe
"#https?"
do
context
"when a certificate is present"
do
subject
{
build
(
:pages_domain
)
}
it
{
is_expected
.
to
be_https
}
end
context
"when no certificate is present"
do
subject
{
build
(
:pages_domain
,
:without_certificate
)
}
it
{
is_expected
.
not_to
be_https
}
end
end
describe
'#update_daemon'
do
describe
'#update_daemon'
do
it
'runs when the domain is created'
do
it
'runs when the domain is created'
do
domain
=
build
(
:pages_domain
)
domain
=
build
(
:pages_domain
)
...
@@ -267,29 +314,30 @@ describe PagesDomain do
...
@@ -267,29 +314,30 @@ describe PagesDomain do
end
end
context
'TLS configuration'
do
context
'TLS configuration'
do
set
(
:domain_with_tls
)
{
create
(
:pages_domain
,
:with_key
,
:with_certificate
)
}
set
(
:domain_without_tls
)
{
create
(
:pages_domain
,
:without_certificate
,
:without_key
)
}
set
(
:domain
)
{
create
(
:pages_domain
)
}
let
(
:cert1
)
{
domain
_with_tls
.
certificate
}
let
(
:cert1
)
{
domain
.
certificate
}
let
(
:cert2
)
{
cert1
+
' '
}
let
(
:cert2
)
{
cert1
+
' '
}
let
(
:key1
)
{
domain
_with_tls
.
key
}
let
(
:key1
)
{
domain
.
key
}
let
(
:key2
)
{
key1
+
' '
}
let
(
:key2
)
{
key1
+
' '
}
it
'updates when added'
do
it
'updates when added'
do
expect
(
domain
).
to
receive
(
:update_daemon
)
expect
(
domain
_without_tls
).
to
receive
(
:update_daemon
)
domain
.
update!
(
key:
key1
,
certificate:
cert1
)
domain
_without_tls
.
update!
(
key:
key1
,
certificate:
cert1
)
end
end
it
'updates when changed'
do
it
'updates when changed'
do
expect
(
domain
_with_tls
).
to
receive
(
:update_daemon
)
expect
(
domain
).
to
receive
(
:update_daemon
)
domain
_with_tls
.
update!
(
key:
key2
,
certificate:
cert2
)
domain
.
update!
(
key:
key2
,
certificate:
cert2
)
end
end
it
'updates when removed'
do
it
'updates when removed'
do
expect
(
domain
_with_tls
).
to
receive
(
:update_daemon
)
expect
(
domain
).
to
receive
(
:update_daemon
)
domain
_with_tls
.
update!
(
key:
nil
,
certificate:
nil
)
domain
.
update!
(
key:
nil
,
certificate:
nil
)
end
end
end
end
end
end
...
...
spec/models/project_spec.rb
View file @
9d45951f
...
@@ -3479,4 +3479,49 @@ describe Project do
...
@@ -3479,4 +3479,49 @@ describe Project do
end
end
end
end
end
end
describe
"#pages_https_only?"
do
subject
{
build
(
:project
)
}
context
"when HTTPS pages are disabled"
do
it
{
is_expected
.
not_to
be_pages_https_only
}
end
context
"when HTTPS pages are enabled"
,
:https_pages_enabled
do
it
{
is_expected
.
to
be_pages_https_only
}
end
end
describe
"#pages_https_only? validation"
,
:https_pages_enabled
do
subject
(
:project
)
do
# set-up dirty object:
create
(
:project
,
pages_https_only:
false
).
tap
do
|
p
|
p
.
pages_https_only
=
true
end
end
context
"when no domains are associated"
do
it
{
is_expected
.
to
be_valid
}
end
context
"when domains including keys and certificates are associated"
do
before
do
allow
(
project
)
.
to
receive
(
:pages_domains
)
.
and_return
([
instance_double
(
PagesDomain
,
https?:
true
)])
end
it
{
is_expected
.
to
be_valid
}
end
context
"when domains including no keys or certificates are associated"
do
before
do
allow
(
project
)
.
to
receive
(
:pages_domains
)
.
and_return
([
instance_double
(
PagesDomain
,
https?:
false
)])
end
it
{
is_expected
.
not_to
be_valid
}
end
end
end
end
spec/requests/api/pages_domains_spec.rb
View file @
9d45951f
require
'rails_helper'
require
'rails_helper'
describe
API
::
PagesDomains
do
describe
API
::
PagesDomains
do
set
(
:project
)
{
create
(
:project
,
path:
'my.project'
)
}
set
(
:project
)
{
create
(
:project
,
path:
'my.project'
,
pages_https_only:
false
)
}
set
(
:user
)
{
create
(
:user
)
}
set
(
:user
)
{
create
(
:user
)
}
set
(
:admin
)
{
create
(
:admin
)
}
set
(
:admin
)
{
create
(
:admin
)
}
set
(
:pages_domain
)
{
create
(
:pages_domain
,
domain:
'www.domain.test'
,
project:
project
)
}
set
(
:pages_domain
)
{
create
(
:pages_domain
,
:without_key
,
:without_certificate
,
domain:
'www.domain.test'
,
project:
project
)
}
set
(
:pages_domain_secure
)
{
create
(
:pages_domain
,
:with_certificate
,
:with_key
,
domain:
'ssl.domain.test'
,
project:
project
)
}
set
(
:pages_domain_secure
)
{
create
(
:pages_domain
,
domain:
'ssl.domain.test'
,
project:
project
)
}
set
(
:pages_domain_expired
)
{
create
(
:pages_domain
,
:with_expired_certificate
,
:with_key
,
domain:
'expired.domain.test'
,
project:
project
)
}
set
(
:pages_domain_expired
)
{
create
(
:pages_domain
,
:with_expired_certificate
,
domain:
'expired.domain.test'
,
project:
project
)
}
let
(
:pages_domain_params
)
{
build
(
:pages_domain
,
domain:
'www.other-domain.test'
).
slice
(
:domain
)
}
let
(
:pages_domain_params
)
{
build
(
:pages_domain
,
:without_key
,
:without_certificate
,
domain:
'www.other-domain.test'
).
slice
(
:domain
)
}
let
(
:pages_domain_secure_params
)
{
build
(
:pages_domain
,
:with_certificate
,
:with_key
,
domain:
'ssl.other-domain.test'
,
project:
project
).
slice
(
:domain
,
:certificate
,
:key
)
}
let
(
:pages_domain_secure_params
)
{
build
(
:pages_domain
,
domain:
'ssl.other-domain.test'
,
project:
project
).
slice
(
:domain
,
:certificate
,
:key
)
}
let
(
:pages_domain_secure_key_missmatch_params
)
{
build
(
:pages_domain
,
:with_trusted_chain
,
:with_key
,
project:
project
).
slice
(
:domain
,
:certificate
,
:key
)
}
let
(
:pages_domain_secure_key_missmatch_params
)
{
build
(
:pages_domain
,
:with_trusted_chain
,
project:
project
).
slice
(
:domain
,
:certificate
,
:key
)
}
let
(
:pages_domain_secure_missing_chain_params
)
{
build
(
:pages_domain
,
:with_missing_chain
,
project:
project
).
slice
(
:certificate
)
}
let
(
:pages_domain_secure_missing_chain_params
)
{
build
(
:pages_domain
,
:with_missing_chain
,
project:
project
).
slice
(
:certificate
)
}
let
(
:route
)
{
"/projects/
#{
project
.
id
}
/pages/domains"
}
let
(
:route
)
{
"/projects/
#{
project
.
id
}
/pages/domains"
}
...
...
spec/services/projects/update_service_spec.rb
View file @
9d45951f
...
@@ -241,6 +241,27 @@ describe Projects::UpdateService do
...
@@ -241,6 +241,27 @@ describe Projects::UpdateService do
})
})
end
end
end
end
context
'when updating #pages_https_only'
,
:https_pages_enabled
do
subject
(
:call_service
)
do
update_project
(
project
,
admin
,
pages_https_only:
false
)
end
it
'updates the attribute'
do
expect
{
call_service
}
.
to
change
{
project
.
pages_https_only?
}
.
to
(
false
)
end
it
'calls Projects::UpdatePagesConfigurationService'
do
expect
(
Projects
::
UpdatePagesConfigurationService
)
.
to
receive
(
:new
)
.
with
(
project
)
.
and_call_original
call_service
end
end
end
end
describe
'#run_auto_devops_pipeline?'
do
describe
'#run_auto_devops_pipeline?'
do
...
...
spec/spec_helper.rb
View file @
9d45951f
...
@@ -197,6 +197,22 @@ RSpec.configure do |config|
...
@@ -197,6 +197,22 @@ RSpec.configure do |config|
Ability
.
allowed?
(
*
args
)
Ability
.
allowed?
(
*
args
)
end
end
end
end
config
.
before
(
:each
,
:http_pages_enabled
)
do
|
_
|
allow
(
Gitlab
.
config
.
pages
).
to
receive
(
:external_http
).
and_return
([
'1.1.1.1:80'
])
end
config
.
before
(
:each
,
:https_pages_enabled
)
do
|
_
|
allow
(
Gitlab
.
config
.
pages
).
to
receive
(
:external_https
).
and_return
([
'1.1.1.1:443'
])
end
config
.
before
(
:each
,
:http_pages_disabled
)
do
|
_
|
allow
(
Gitlab
.
config
.
pages
).
to
receive
(
:external_http
).
and_return
(
false
)
end
config
.
before
(
:each
,
:https_pages_disabled
)
do
|
_
|
allow
(
Gitlab
.
config
.
pages
).
to
receive
(
:external_https
).
and_return
(
false
)
end
end
end
# add simpler way to match asset paths containing digest strings
# add simpler way to match asset paths containing digest strings
...
...
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