summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLukas Reschke <lukas@owncloud.com>2015-01-19 11:56:04 +0100
committerLukas Reschke <lukas@owncloud.com>2015-03-02 19:07:46 +0100
commitbbd5f2841561911461d992483cab54f5c18fa342 (patch)
tree113e9ab1919c8fb42a7fd90db79139b783a643c9
parent1155ad6e389e47e110a415f22eddda1570dc9ff2 (diff)
downloadnextcloud-server-bbd5f2841561911461d992483cab54f5c18fa342.tar.gz
nextcloud-server-bbd5f2841561911461d992483cab54f5c18fa342.zip
Let users configure security headers in their Webserver
Doing this in the PHP code is not the right approach for multiple reasons: 1. A bug in the PHP code prevents them from being added to the response. 2. They are only added when something is served via PHP and not in other cases (that makes for example the newest IE UXSS which is not yet patched by Microsoft exploitable on ownCloud) 3. Some headers such as the Strict-Transport-Security might require custom modifications by administrators. This was not possible before and lead to buggy situations. This pull request moves those headers out of the PHP code and adds a security check to the admin settings performed via JS.
-rw-r--r--.htaccess4
-rw-r--r--config/config.sample.php19
-rw-r--r--core/js/core.json1
-rw-r--r--core/js/js.js8
-rw-r--r--core/js/setupchecks.js96
-rw-r--r--core/js/tests/specs/setupchecksSpec.js326
-rw-r--r--lib/base.php33
-rw-r--r--lib/private/appframework/app.php2
-rw-r--r--lib/private/appframework/http/request.php2
-rw-r--r--lib/private/response.php12
-rw-r--r--lib/private/user/session.php2
-rw-r--r--settings/admin.php5
-rw-r--r--settings/controller/securitysettingscontroller.php37
-rw-r--r--settings/js/admin.js33
-rw-r--r--settings/routes.php2
-rw-r--r--settings/templates/admin.php59
-rw-r--r--tests/settings/controller/securitysettingscontrollertest.php71
17 files changed, 445 insertions, 267 deletions
diff --git a/.htaccess b/.htaccess
index d79ee9f8871..5e24a35743d 100644
--- a/.htaccess
+++ b/.htaccess
@@ -45,6 +45,10 @@ Options -Indexes
ModPagespeed Off
</IfModule>
<IfModule mod_headers.c>
+ Header set X-Content-Type-Options "nosniff"
+ Header set X-XSS-Protection "1; mode=block"
+ Header set X-Robots-Tag "none"
+ Header set X-Frame-Options "SAMEORIGIN"
<FilesMatch "\.(css|js)$">
Header set Cache-Control "max-age=7200, public"
</FilesMatch>
diff --git a/config/config.sample.php b/config/config.sample.php
index 1b3477417ff..16575cf82ed 100644
--- a/config/config.sample.php
+++ b/config/config.sample.php
@@ -745,18 +745,6 @@ $CONFIG = array(
*/
/**
- * Change this to ``true`` to require HTTPS for all connections, and to reject
- * HTTP requests.
- */
-'forcessl' => false,
-
-/**
- * Change this to ``true`` to require HTTPS connections also for all subdomains.
- * Works only together when `forcessl` is set to true.
- */
-'forceSSLforSubdomains' => false,
-
-/**
* Extra SSL options to be used for configuration.
*/
'openssl' => array(
@@ -787,13 +775,6 @@ $CONFIG = array(
'theme' => '',
/**
- * X-Frame-Restriction is a header which prevents browsers from showing the site
- * inside an iframe. This is be used to prevent clickjacking. It is risky to
- * disable this, so leave it set at ``true``.
- */
-'xframe_restriction' => true,
-
-/**
* The default cipher for encrypting files. Currently AES-128-CFB and
* AES-256-CFB are supported.
*/
diff --git a/core/js/core.json b/core/js/core.json
index 7f3b313e898..b32ca5ca8f3 100644
--- a/core/js/core.json
+++ b/core/js/core.json
@@ -24,6 +24,7 @@
"config.js",
"multiselect.js",
"oc-requesttoken.js",
+ "setupchecks.js",
"../search/js/search.js"
]
}
diff --git a/core/js/js.js b/core/js/js.js
index 1e9ae4cc695..f24694124ad 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -211,6 +211,14 @@ var OC={
},
/**
+ * Protocol that is used to access this ownCloud instance
+ * @return {string} Used protocol
+ */
+ getProtocol: function() {
+ return window.location.protocol.split(':')[0];
+ },
+
+ /**
* get the absolute path to an image file
* if no extension is given for the image, it will automatically decide
* between .png and .svg based on what the browser supports
diff --git a/core/js/setupchecks.js b/core/js/setupchecks.js
index 00e73162c55..d5bd1c465b2 100644
--- a/core/js/setupchecks.js
+++ b/core/js/setupchecks.js
@@ -70,7 +70,101 @@
url: OC.generateUrl('settings/ajax/checksetup')
}).then(afterCall, afterCall);
return deferred.promise();
+ },
+
+ /**
+ * Runs generic checks on the server side, the difference to dedicated
+ * methods is that we use the same XHR object for all checks to save
+ * requests.
+ *
+ * @return $.Deferred object resolved with an array of error messages
+ */
+ checkGeneric: function() {
+ var self = this;
+ var deferred = $.Deferred();
+ var afterCall = function(data, statusText, xhr) {
+ var messages = [];
+ messages = messages.concat(self._checkSecurityHeaders(xhr));
+ messages = messages.concat(self._checkSSL(xhr));
+ deferred.resolve(messages);
+ };
+
+ $.ajax({
+ type: 'GET',
+ url: OC.generateUrl('heartbeat')
+ }).then(afterCall, afterCall);
+
+ return deferred.promise();
+ },
+
+ /**
+ * Runs check for some generic security headers on the server side
+ *
+ * @param {Object} xhr
+ * @return {Array} Array with error messages
+ */
+ _checkSecurityHeaders: function(xhr) {
+ var messages = [];
+
+ if (xhr.status === 200) {
+ var securityHeaders = {
+ 'X-XSS-Protection': '1; mode=block',
+ 'X-Content-Type-Options': 'nosniff',
+ 'X-Robots-Tag': 'none',
+ 'X-Frame-Options': 'SAMEORIGIN'
+ };
+
+ for (var header in securityHeaders) {
+ if(xhr.getResponseHeader(header) !== securityHeaders[header]) {
+ messages.push(
+ t('core', 'The "{header}" HTTP header is not configured to equal to "{expected}". This is a potential security risk and we recommend adjusting this setting.', {header: header, expected: securityHeaders[header]})
+ );
+ }
+ }
+ } else {
+ messages.push(t('core', 'Error occurred while checking server setup'));
+ }
+
+ return messages;
+ },
+
+ /**
+ * Runs check for some SSL configuration issues on the server side
+ *
+ * @param {Object} xhr
+ * @return {Array} Array with error messages
+ */
+ _checkSSL: function(xhr) {
+ var messages = [];
+
+ if (xhr.status === 200) {
+ if(OC.getProtocol() === 'https') {
+ // Extract the value of 'Strict-Transport-Security'
+ var transportSecurityValidity = xhr.getResponseHeader('Strict-Transport-Security');
+ if(transportSecurityValidity !== null && transportSecurityValidity.length > 8) {
+ var firstComma = transportSecurityValidity.indexOf(";");
+ if(firstComma !== -1) {
+ transportSecurityValidity = transportSecurityValidity.substring(0, firstComma);
+ } else {
+ transportSecurityValidity = transportSecurityValidity.substring(8);
+ }
+ }
+
+ if(isNaN(transportSecurityValidity) || transportSecurityValidity <= 2678399) {
+ messages.push(
+ t('core', 'The "Strict-Transport-Security" HTTP header is not configured to least "2,678,400" seconds. This is a potential security risk and we recommend adjusting this setting.')
+ );
+ }
+ } else {
+ messages.push(
+ t('core', 'You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead.')
+ );
+ }
+ } else {
+ messages.push(t('core', 'Error occurred while checking server setup'));
+ }
+
+ return messages;
}
};
})();
-
diff --git a/core/js/tests/specs/setupchecksSpec.js b/core/js/tests/specs/setupchecksSpec.js
new file mode 100644
index 00000000000..2fb0989d627
--- /dev/null
+++ b/core/js/tests/specs/setupchecksSpec.js
@@ -0,0 +1,326 @@
+/**
+ * Copyright (c) 2015 Lukas Reschke <lukas@owncloud.com>
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+describe('OC.SetupChecks tests', function() {
+ var suite = this;
+
+ beforeEach( function(){
+ suite.server = sinon.fakeServer.create();
+ });
+
+ afterEach( function(){
+ suite.server.restore();
+ });
+
+ describe('checkWebDAV', function() {
+ it('should fail with another response status code than 201 or 207', function(done) {
+ var async = OC.SetupChecks.checkWebDAV();
+
+ suite.server.requests[0].respond(200);
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual(['Your web server is not yet set up properly to allow file synchronization because the WebDAV interface seems to be broken.']);
+ });
+ });
+
+ it('should return no error with a response status code of 207', function(done) {
+ var async = OC.SetupChecks.checkWebDAV();
+
+ suite.server.requests[0].respond(207);
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual([]);
+ });
+ });
+
+ it('should return no error with a response status code of 401', function(done) {
+ var async = OC.SetupChecks.checkWebDAV();
+
+ suite.server.requests[0].respond(401);
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual([]);
+ });
+ });
+ });
+
+ describe('checkSetup', function() {
+ it('should return an error if server has no internet connection', function(done) {
+ var async = OC.SetupChecks.checkSetup();
+
+ suite.server.requests[0].respond(
+ 200,
+ {
+ 'Content-Type': 'application/json'
+ },
+ JSON.stringify({data: {serverHasInternetConnection: false}})
+ );
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual(['This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features.', 'Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root.']);
+ });
+ });
+
+ it('should return an error if server has no internet connection and data directory is not protected', function(done) {
+ var async = OC.SetupChecks.checkSetup();
+
+ suite.server.requests[0].respond(
+ 200,
+ {
+ 'Content-Type': 'application/json'
+ },
+ JSON.stringify({data: {serverHasInternetConnection: false, dataDirectoryProtected: false}})
+ );
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual(['This server has no working Internet connection. This means that some of the features like mounting external storage, notifications about updates or installation of third-party apps will not work. Accessing files remotely and sending of notification emails might not work, either. We suggest to enable Internet connection for this server if you want to have all features.', 'Your data directory and your files are probably accessible from the Internet. The .htaccess file is not working. We strongly suggest that you configure your web server in a way that the data directory is no longer accessible or you move the data directory outside the web server document root.']);
+ });
+ });
+
+ it('should return an error if the response has no statuscode 200', function(done) {
+ var async = OC.SetupChecks.checkSetup();
+
+ suite.server.requests[0].respond(
+ 500,
+ {
+ 'Content-Type': 'application/json'
+ },
+ JSON.stringify({data: {serverHasInternetConnection: false, dataDirectoryProtected: false}})
+ );
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual(['Error occurred while checking server setup']);
+ });
+ });
+ });
+
+ describe('checkGeneric', function() {
+ it('should return an error if the response has no statuscode 200', function(done) {
+ var async = OC.SetupChecks.checkGeneric();
+
+ suite.server.requests[0].respond(
+ 500,
+ {
+ 'Content-Type': 'application/json'
+ }
+ );
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual(['Error occurred while checking server setup', 'Error occurred while checking server setup']);
+ });
+ });
+
+ it('should return all errors if all headers are missing', function(done) {
+ var protocolStub = sinon.stub(OC, 'getProtocol').returns('https');
+ var async = OC.SetupChecks.checkGeneric();
+
+ suite.server.requests[0].respond(
+ 200,
+ {
+ 'Content-Type': 'application/json',
+ 'Strict-Transport-Security': '2678400'
+ }
+ );
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual(['The "X-XSS-Protection" HTTP header is not configured to equal to "1; mode=block". This is a potential security risk and we recommend adjusting this setting.', 'The "X-Content-Type-Options" HTTP header is not configured to equal to "nosniff". This is a potential security risk and we recommend adjusting this setting.', 'The "X-Robots-Tag" HTTP header is not configured to equal to "none". This is a potential security risk and we recommend adjusting this setting.', 'The "X-Frame-Options" HTTP header is not configured to equal to "SAMEORIGIN". This is a potential security risk and we recommend adjusting this setting.']);
+ });
+ protocolStub.restore();
+ });
+
+ it('should return only some errors if just some headers are missing', function(done) {
+ var protocolStub = sinon.stub(OC, 'getProtocol').returns('https');
+ var async = OC.SetupChecks.checkGeneric();
+
+ suite.server.requests[0].respond(
+ 200,
+ {
+ 'X-Robots-Tag': 'none',
+ 'X-Frame-Options': 'SAMEORIGIN',
+ 'Strict-Transport-Security': '2678400'
+
+ }
+ );
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual(['The "X-XSS-Protection" HTTP header is not configured to equal to "1; mode=block". This is a potential security risk and we recommend adjusting this setting.', 'The "X-Content-Type-Options" HTTP header is not configured to equal to "nosniff". This is a potential security risk and we recommend adjusting this setting.']);
+ });
+ protocolStub.restore();
+ });
+
+ it('should return none errors if all headers are there', function(done) {
+ var protocolStub = sinon.stub(OC, 'getProtocol').returns('https');
+ var async = OC.SetupChecks.checkGeneric();
+
+ suite.server.requests[0].respond(
+ 200,
+ {
+ 'X-XSS-Protection': '1; mode=block',
+ 'X-Content-Type-Options': 'nosniff',
+ 'X-Robots-Tag': 'none',
+ 'X-Frame-Options': 'SAMEORIGIN',
+ 'Strict-Transport-Security': '2678400'
+ }
+ );
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual([]);
+ });
+ protocolStub.restore();
+ });
+ });
+
+ it('should return a SSL warning if HTTPS is not used', function(done) {
+ var protocolStub = sinon.stub(OC, 'getProtocol').returns('http');
+ var async = OC.SetupChecks.checkGeneric();
+
+ suite.server.requests[0].respond(200,
+ {
+ 'X-XSS-Protection': '1; mode=block',
+ 'X-Content-Type-Options': 'nosniff',
+ 'X-Robots-Tag': 'none',
+ 'X-Frame-Options': 'SAMEORIGIN'
+ }
+ );
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual(['You are accessing this site via HTTP. We strongly suggest you configure your server to require using HTTPS instead.']);
+ });
+ protocolStub.restore();
+ });
+
+ it('should return an error if the response has no statuscode 200', function(done) {
+ var async = OC.SetupChecks.checkGeneric();
+
+ suite.server.requests[0].respond(
+ 500,
+ {
+ 'Content-Type': 'application/json'
+ },
+ JSON.stringify({data: {serverHasInternetConnection: false, dataDirectoryProtected: false}})
+ );
+ async.done(function( data, s, x ){
+ expect(data).toEqual(['Error occurred while checking server setup', 'Error occurred while checking server setup']);
+ });
+ });
+
+ it('should return a SSL warning if SSL used without Strict-Transport-Security-Header', function(done) {
+ var protocolStub = sinon.stub(OC, 'getProtocol').returns('https');
+ var async = OC.SetupChecks.checkGeneric();
+
+ suite.server.requests[0].respond(200,
+ {
+ 'X-XSS-Protection': '1; mode=block',
+ 'X-Content-Type-Options': 'nosniff',
+ 'X-Robots-Tag': 'none',
+ 'X-Frame-Options': 'SAMEORIGIN'
+ }
+ );
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual(['The "Strict-Transport-Security" HTTP header is not configured to least "2,678,400" seconds. This is a potential security risk and we recommend adjusting this setting.']);
+ });
+ protocolStub.restore();
+ });
+
+ it('should return a SSL warning if SSL used with to small Strict-Transport-Security-Header', function(done) {
+ var protocolStub = sinon.stub(OC, 'getProtocol').returns('https');
+ var async = OC.SetupChecks.checkGeneric();
+
+ suite.server.requests[0].respond(200,
+ {
+ 'Strict-Transport-Security': '2678399',
+ 'X-XSS-Protection': '1; mode=block',
+ 'X-Content-Type-Options': 'nosniff',
+ 'X-Robots-Tag': 'none',
+ 'X-Frame-Options': 'SAMEORIGIN'
+ }
+ );
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual(['The "Strict-Transport-Security" HTTP header is not configured to least "2,678,400" seconds. This is a potential security risk and we recommend adjusting this setting.']);
+ });
+ protocolStub.restore();
+ });
+
+ it('should return a SSL warning if SSL used with to a bogus Strict-Transport-Security-Header', function(done) {
+ var protocolStub = sinon.stub(OC, 'getProtocol').returns('https');
+ var async = OC.SetupChecks.checkGeneric();
+
+ suite.server.requests[0].respond(200,
+ {
+ 'Strict-Transport-Security': 'iAmABogusHeader342',
+ 'X-XSS-Protection': '1; mode=block',
+ 'X-Content-Type-Options': 'nosniff',
+ 'X-Robots-Tag': 'none',
+ 'X-Frame-Options': 'SAMEORIGIN'
+ }
+ );
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual(['The "Strict-Transport-Security" HTTP header is not configured to least "2,678,400" seconds. This is a potential security risk and we recommend adjusting this setting.']);
+ });
+ protocolStub.restore();
+ });
+
+ it('should return no SSL warning if SSL used with to exact the minimum Strict-Transport-Security-Header', function(done) {
+ var protocolStub = sinon.stub(OC, 'getProtocol').returns('https');
+ var async = OC.SetupChecks.checkGeneric();
+
+ suite.server.requests[0].respond(200, {
+ 'Strict-Transport-Security': '2678400',
+ 'X-XSS-Protection': '1; mode=block',
+ 'X-Content-Type-Options': 'nosniff',
+ 'X-Robots-Tag': 'none',
+ 'X-Frame-Options': 'SAMEORIGIN'
+ });
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual([]);
+ });
+ protocolStub.restore();
+ });
+
+ it('should return no SSL warning if SSL used with to more than the minimum Strict-Transport-Security-Header', function(done) {
+ var protocolStub = sinon.stub(OC, 'getProtocol').returns('https');
+ var async = OC.SetupChecks.checkGeneric();
+
+ suite.server.requests[0].respond(200, {
+ 'Strict-Transport-Security': '12678400',
+ 'X-XSS-Protection': '1; mode=block',
+ 'X-Content-Type-Options': 'nosniff',
+ 'X-Robots-Tag': 'none',
+ 'X-Frame-Options': 'SAMEORIGIN'
+ });
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual([]);
+ });
+ protocolStub.restore();
+ });
+
+ it('should return no SSL warning if SSL used with to more than the minimum Strict-Transport-Security-Header and includeSubDomains parameter', function(done) {
+ var protocolStub = sinon.stub(OC, 'getProtocol').returns('https');
+ var async = OC.SetupChecks.checkGeneric();
+
+ suite.server.requests[0].respond(200, {
+ 'Strict-Transport-Security': '12678400; includeSubDomains',
+ 'X-XSS-Protection': '1; mode=block',
+ 'X-Content-Type-Options': 'nosniff',
+ 'X-Robots-Tag': 'none',
+ 'X-Frame-Options': 'SAMEORIGIN'
+ });
+
+ async.done(function( data, s, x ){
+ expect(data).toEqual([]);
+ });
+ protocolStub.restore();
+ });
+});
diff --git a/lib/base.php b/lib/base.php
index 1f2e90deefd..84616090ec8 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -247,34 +247,6 @@ class OC {
}
}
- public static function checkSSL() {
- $request = \OC::$server->getRequest();
-
- // redirect to https site if configured
- if (\OC::$server->getSystemConfig()->getValue('forcessl', false)) {
- // Default HSTS policy
- $header = 'Strict-Transport-Security: max-age=31536000';
-
- // If SSL for subdomains is enabled add "; includeSubDomains" to the header
- if(\OC::$server->getSystemConfig()->getValue('forceSSLforSubdomains', false)) {
- $header .= '; includeSubDomains';
- }
- header($header);
- ini_set('session.cookie_secure', true);
-
- if ($request->getServerProtocol() <> 'https' && !OC::$CLI) {
- $url = 'https://' . $request->getServerHost() . $request->getRequestUri();
- header("Location: $url");
- exit();
- }
- } else {
- // Invalidate HSTS headers
- if ($request->getServerProtocol() === 'https') {
- header('Strict-Transport-Security: max-age=0');
- }
- }
- }
-
public static function checkMaintenanceMode() {
// Allow ajax update script to execute without being stopped
if (\OC::$server->getSystemConfig()->getValue('maintenance', false) && OC::$SUBURI != '/core/ajax/update.php') {
@@ -569,8 +541,11 @@ class OC {
self::initTemplateEngine();
self::checkConfig();
self::checkInstalled();
- self::checkSSL();
+
OC_Response::addSecurityHeaders();
+ if(self::$server->getRequest()->getServerProtocol() === 'https') {
+ ini_set('session.cookie_secure', true);
+ }
$errors = OC_Util::checkServer(\OC::$server->getConfig());
if (count($errors) > 0) {
diff --git a/lib/private/appframework/app.php b/lib/private/appframework/app.php
index 6d54b931d5a..1e1915c85d8 100644
--- a/lib/private/appframework/app.php
+++ b/lib/private/appframework/app.php
@@ -123,7 +123,7 @@ class App {
$expireDate,
$container->getServer()->getWebRoot(),
null,
- $container->getServer()->getConfig()->getSystemValue('forcessl', false),
+ $container->getServer()->getRequest()->getServerProtocol() === 'https',
true
);
}
diff --git a/lib/private/appframework/http/request.php b/lib/private/appframework/http/request.php
index f6a89b358db..b1b4b713287 100644
--- a/lib/private/appframework/http/request.php
+++ b/lib/private/appframework/http/request.php
@@ -475,7 +475,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
private function isOverwriteCondition($type = '') {
$regex = '/' . $this->config->getSystemValue('overwritecondaddr', '') . '/';
return $regex === '//' || preg_match($regex, $this->server['REMOTE_ADDR']) === 1
- || ($type !== 'protocol' && $this->config->getSystemValue('forcessl', false));
+ || $type !== 'protocol';
}
/**
diff --git a/lib/private/response.php b/lib/private/response.php
index 600b702810c..2bec5e3decd 100644
--- a/lib/private/response.php
+++ b/lib/private/response.php
@@ -195,15 +195,6 @@ class OC_Response {
* components (e.g. SabreDAV) also benefit from this headers.
*/
public static function addSecurityHeaders() {
- header('X-XSS-Protection: 1; mode=block'); // Enforce browser based XSS filters
- header('X-Content-Type-Options: nosniff'); // Disable sniffing the content type for IE
-
- // iFrame Restriction Policy
- $xFramePolicy = OC_Config::getValue('xframe_restriction', true);
- if ($xFramePolicy) {
- header('X-Frame-Options: Sameorigin'); // Disallow iFraming from other domains
- }
-
/**
* FIXME: Content Security Policy for legacy ownCloud components. This
* can be removed once \OCP\AppFramework\Http\Response from the AppFramework
@@ -219,9 +210,6 @@ class OC_Response {
. 'media-src *; '
. 'connect-src *';
header('Content-Security-Policy:' . $policy);
-
- // https://developers.google.com/webmasters/control-crawl-index/docs/robots_meta_tag
- header('X-Robots-Tag: none');
}
}
diff --git a/lib/private/user/session.php b/lib/private/user/session.php
index 67a4c7a4361..a7567952053 100644
--- a/lib/private/user/session.php
+++ b/lib/private/user/session.php
@@ -265,7 +265,7 @@ class Session implements IUserSession, Emitter {
* @param string $token
*/
public function setMagicInCookie($username, $token) {
- $secureCookie = \OC_Config::getValue("forcessl", false); //TODO: DI for cookies and OC_Config
+ $secureCookie = \OC::$server->getRequest()->getServerProtocol() === 'https';
$expires = time() + \OC_Config::getValue('remember_login_cookie_lifetime', 60 * 60 * 24 * 15);
setcookie("oc_username", $username, $expires, \OC::$WEBROOT, '', $secureCookie, true);
setcookie("oc_token", $token, $expires, \OC::$WEBROOT, '', $secureCookie, true);
diff --git a/settings/admin.php b/settings/admin.php
index 95940db7282..da25ab55a93 100644
--- a/settings/admin.php
+++ b/settings/admin.php
@@ -58,11 +58,6 @@ $excludedGroupsList = $appConfig->getValue('core', 'shareapi_exclude_groups_list
$excludedGroupsList = explode(',', $excludedGroupsList); // FIXME: this should be JSON!
$template->assign('shareExcludedGroupsList', implode('|', $excludedGroupsList));
-// Check if connected using HTTPS
-$template->assign('isConnectedViaHTTPS', $request->getServerProtocol() === 'https');
-$template->assign('enforceHTTPSEnabled', $config->getSystemValue('forcessl', false));
-$template->assign('forceSSLforSubdomainsEnabled', $config->getSystemValue('forceSSLforSubdomains', false));
-
// If the current web root is non-empty but the web root from the config is,
// and system cron is used, the URL generator fails to build valid URLs.
$shouldSuggestOverwriteCliUrl = $config->getAppValue('core', 'backgroundjobs_mode', 'ajax') === 'cron' &&
diff --git a/settings/controller/securitysettingscontroller.php b/settings/controller/securitysettingscontroller.php
index af60df8dc3b..50e70ebb70e 100644
--- a/settings/controller/securitysettingscontroller.php
+++ b/settings/controller/securitysettingscontroller.php
@@ -43,43 +43,6 @@ class SecuritySettingsController extends Controller {
}
/**
- * @return array
- */
- protected function returnError() {
- return array(
- 'status' => 'error'
- );
- }
-
- /**
- * Enforce or disable the enforcement of SSL
- * @param boolean $enforceHTTPS Whether SSL should be enforced
- * @return array
- */
- public function enforceSSL($enforceHTTPS = false) {
- if(!is_bool($enforceHTTPS)) {
- return $this->returnError();
- }
- $this->config->setSystemValue('forcessl', $enforceHTTPS);
-
- return $this->returnSuccess();
- }
-
- /**
- * Enforce or disable the enforcement for SSL on subdomains
- * @param bool $forceSSLforSubdomains Whether SSL on subdomains should be enforced
- * @return array
- */
- public function enforceSSLForSubdomains($forceSSLforSubdomains = false) {
- if(!is_bool($forceSSLforSubdomains)) {
- return $this->returnError();
- }
- $this->config->setSystemValue('forceSSLforSubdomains', $forceSSLforSubdomains);
-
- return $this->returnSuccess();
- }
-
- /**
* Add a new trusted domain
* @param string $newTrustedDomain The newly to add trusted domain
* @return array
diff --git a/settings/js/admin.js b/settings/js/admin.js
index 34bc2466048..9fe4226827c 100644
--- a/settings/js/admin.js
+++ b/settings/js/admin.js
@@ -75,32 +75,6 @@ $(document).ready(function(){
$('#setDefaultExpireDate').toggleClass('hidden', !(this.checked && $('#shareapiDefaultExpireDate')[0].checked));
});
- $('#forcessl').change(function(){
- $(this).val(($(this).val() !== 'true'));
- var forceSSLForSubdomain = $('#forceSSLforSubdomainsSpan');
-
- $.post(OC.generateUrl('settings/admin/security/ssl'), {
- enforceHTTPS: $(this).val()
- },function(){} );
-
- if($(this).val() === 'true') {
- forceSSLForSubdomain.prop('disabled', false);
- forceSSLForSubdomain.removeClass('hidden');
- } else {
- forceSSLForSubdomain.prop('disabled', true);
- forceSSLForSubdomain.addClass('hidden');
- }
- });
-
- $('#forceSSLforSubdomains').change(function(){
- $(this).val(($(this).val() !== 'true'));
-
- $.post(OC.generateUrl('settings/admin/security/ssl/subdomains'), {
- forceSSLforSubdomains: $(this).val()
- },function(){} );
- });
-
-
$('#mail_smtpauth').change(function() {
if (!this.checked) {
$('#mail_credentials').addClass('hidden');
@@ -158,9 +132,10 @@ $(document).ready(function(){
// run setup checks then gather error messages
$.when(
OC.SetupChecks.checkWebDAV(),
- OC.SetupChecks.checkSetup()
- ).then(function(check1, check2) {
- var errors = [].concat(check1, check2);
+ OC.SetupChecks.checkSetup(),
+ OC.SetupChecks.checkGeneric()
+ ).then(function(check1, check2, check3) {
+ var errors = [].concat(check1, check2, check3);
var $el = $('#postsetupchecks');
var $errorsEl;
$el.find('.loading').addClass('hidden');
diff --git a/settings/routes.php b/settings/routes.php
index 942d9b0fb28..ea49cc24eb7 100644
--- a/settings/routes.php
+++ b/settings/routes.php
@@ -20,8 +20,6 @@ $application->registerRoutes($this, array(
array('name' => 'MailSettings#sendTestMail', 'url' => '/settings/admin/mailtest', 'verb' => 'POST'),
array('name' => 'AppSettings#listCategories', 'url' => '/settings/apps/categories', 'verb' => 'GET'),
array('name' => 'AppSettings#listApps', 'url' => '/settings/apps/list', 'verb' => 'GET'),
- array('name' => 'SecuritySettings#enforceSSL', 'url' => '/settings/admin/security/ssl', 'verb' => 'POST'),
- array('name' => 'SecuritySettings#enforceSSLForSubdomains', 'url' => '/settings/admin/security/ssl/subdomains', 'verb' => 'POST'),
array('name' => 'SecuritySettings#trustedDomains', 'url' => '/settings/admin/security/trustedDomains', 'verb' => 'POST'),
array('name' => 'Users#setMailAddress', 'url' => '/settings/users/{id}/mailAddress', 'verb' => 'PUT'),
array('name' => 'LogSettings#setLogLevel', 'url' => '/settings/admin/log/level', 'verb' => 'POST'),
diff --git a/settings/templates/admin.php b/settings/templates/admin.php
index 1608aa8123b..b6326108bf6 100644
--- a/settings/templates/admin.php
+++ b/settings/templates/admin.php
@@ -66,20 +66,6 @@ if ($_['mail_smtpmode'] == 'qmail') {
<div id="security-warning">
<?php
-// is ssl working ?
-if (!$_['isConnectedViaHTTPS']) {
- ?>
-<div class="section">
- <h2><?php p($l->t('Security Warning'));?></h2>
-
- <span class="securitywarning">
- <?php p($l->t('You are accessing %s via HTTP. We strongly suggest you configure your server to require using HTTPS instead.', $theme->getTitle())); ?>
- </span>
-
-</div>
-<?php
-}
-
// is read only config enabled
if ($_['readOnlyConfigEnabled']) {
?>
@@ -370,51 +356,6 @@ if ($_['cronErrors']) {
</p>
</div>
-<div class="section" id="security">
- <h2><?php p($l->t('Security'));?></h2>
- <p>
- <input type="checkbox" name="forcessl" id="forcessl"
- <?php if ($_['enforceHTTPSEnabled']) {
- print_unescaped('checked="checked" ');
- print_unescaped('value="true"');
- } else {
- print_unescaped('value="false"');
- }
- ?>
- <?php if (!$_['isConnectedViaHTTPS']) p('disabled'); ?> />
- <label for="forcessl"><?php p($l->t('Enforce HTTPS'));?></label><br/>
- <em><?php p($l->t(
- 'Forces the clients to connect to %s via an encrypted connection.',
- $theme->getName()
- )); ?></em><br/>
- <span id="forceSSLforSubdomainsSpan" <?php if(!$_['enforceHTTPSEnabled']) { print_unescaped('class="hidden"'); } ?>>
- <input type="checkbox" name="forceSSLforSubdomains" id="forceSSLforSubdomains"
- <?php if ($_['forceSSLforSubdomainsEnabled']) {
- print_unescaped('checked="checked" ');
- print_unescaped('value="true"');
- } else {
- print_unescaped('value="false"');
- }
- ?>
- <?php if (!$_['isConnectedViaHTTPS']) { p('disabled'); } ?> />
- <label for="forceSSLforSubdomains"><?php p($l->t('Enforce HTTPS for subdomains'));?></label><br/>
- <em><?php p($l->t(
- 'Forces the clients to connect to %s and subdomains via an encrypted connection.',
- $theme->getName()
- )); ?></em>
- </span>
- <?php if (!$_['isConnectedViaHTTPS']) {
- print_unescaped("<br/><em>");
- p($l->t(
- 'Please connect to your %s via HTTPS to enable or disable the SSL enforcement.',
- $theme->getName()
- ));
- print_unescaped("</em>");
- }
- ?>
- </p>
-</div>
-
<div class="section">
<form id="mail_general_settings" class="mail_settings">
<h2><?php p($l->t('Email Server'));?></h2>
diff --git a/tests/settings/controller/securitysettingscontrollertest.php b/tests/settings/controller/securitysettingscontrollertest.php
index d89e4932368..56848d8df30 100644
--- a/tests/settings/controller/securitysettingscontrollertest.php
+++ b/tests/settings/controller/securitysettingscontrollertest.php
@@ -31,77 +31,6 @@ class SecuritySettingsControllerTest extends \PHPUnit_Framework_TestCase {
$this->securitySettingsController = $this->container['SecuritySettingsController'];
}
-
- public function testEnforceSSLEmpty() {
- $this->container['Config']
- ->expects($this->once())
- ->method('setSystemValue')
- ->with('forcessl', false);
-
- $response = $this->securitySettingsController->enforceSSL();
- $expectedResponse = array('status' => 'success');
-
- $this->assertSame($expectedResponse, $response);
- }
-
- public function testEnforceSSL() {
- $this->container['Config']
- ->expects($this->once())
- ->method('setSystemValue')
- ->with('forcessl', true);
-
- $response = $this->securitySettingsController->enforceSSL(true);
- $expectedResponse = array('status' => 'success');
-
- $this->assertSame($expectedResponse, $response);
- }
-
- public function testEnforceSSLInvalid() {
- $this->container['Config']
- ->expects($this->exactly(0))
- ->method('setSystemValue');
-
- $response = $this->securitySettingsController->enforceSSL('blah');
- $expectedResponse = array('status' => 'error');
-
- $this->assertSame($expectedResponse, $response);
- }
-
- public function testEnforceSSLForSubdomainsEmpty() {
- $this->container['Config']
- ->expects($this->once())
- ->method('setSystemValue')
- ->with('forceSSLforSubdomains', false);
-
- $response = $this->securitySettingsController->enforceSSLForSubdomains();
- $expectedResponse = array('status' => 'success');
-
- $this->assertSame($expectedResponse, $response);
- }
-
- public function testEnforceSSLForSubdomains() {
- $this->container['Config']
- ->expects($this->once())
- ->method('setSystemValue')
- ->with('forceSSLforSubdomains', true);
-
- $response = $this->securitySettingsController->enforceSSLForSubdomains(true);
- $expectedResponse = array('status' => 'success');
-
- $this->assertSame($expectedResponse, $response);
- }
-
- public function testEnforceSSLForSubdomainsInvalid() {
- $this->container['Config']
- ->expects($this->exactly(0))
- ->method('setSystemValue');
-
- $response = $this->securitySettingsController->enforceSSLForSubdomains('blah');
- $expectedResponse = array('status' => 'error');
-
- $this->assertSame($expectedResponse, $response);
- }
-
public function testTrustedDomainsWithExistingValues() {
$this->container['Config']
->expects($this->once())