diff --git a/config/install/seckit.settings.yml b/config/install/seckit.settings.yml
new file mode 100644
index 0000000..0816a3e
--- /dev/null
+++ b/config/install/seckit.settings.yml
@@ -0,0 +1,42 @@
+seckit_xss:
+  csp:
+    checkbox: 0
+    report-only: 0
+    default-src: ''
+    script-src: ''
+    object-src: ''
+    img-src: ''
+    media-src: ''
+    frame-src: ''
+    font-src: ''
+    connect-src: ''
+    report-uri: ''
+    policy-uri: ''
+  x_xss:
+    seckit_x_xss_option_disable: 'Disabled'
+    seckit_x_xss_option_0: '0'
+    seckit_x_xss_option_1: '1; mode=block'
+    select: 0
+seckit_csrf:
+  origin: 1
+  origin_whitelist: ''
+seckit_clickjacking:
+  js_css_noscript: 0
+  noscript_message: ''
+  x_frame:
+    SECKIT_X_FRAME_DISABLE: 'Disabled'
+    SECKIT_X_FRAME_SAMEORIGIN: 'SameOrigin'
+    SECKIT_X_FRAME_DENY: 'Deny'
+    SECKIT_X_FRAME_ALLOW_FROM: 'Allow-From'
+  x_frame_allow_from: ''
+seckit_ssl:
+  hsts: 0
+  hsts_subdomains: 0
+  hsts_max_age: ''
+seckit_various:
+  from_origin: 0
+  from_origin_destination: ''
+
+
+
+
diff --git a/seckit.info.yml b/seckit.info.yml
new file mode 100644
index 0000000..07b39c0
--- /dev/null
+++ b/seckit.info.yml
@@ -0,0 +1,6 @@
+name: Security Kit
+description: "Enhance security of your Drupal website."
+package: Security
+core: 8.x
+configure: seckit.settings
+type: module
diff --git a/seckit.menu_links.yml b/seckit.menu_links.yml
new file mode 100644
index 0000000..3422f97
--- /dev/null
+++ b/seckit.menu_links.yml
@@ -0,0 +1,6 @@
+seckit.admin:
+  title: 'Security Kit settings'
+  description: 'Manage Security Kit settings.'
+  parent: system.admin_config_system
+  route_name: seckit.settings
+  weight: 100
diff --git a/seckit.module b/seckit.module
index 693e76a..204104e 100644
--- a/seckit.module
+++ b/seckit.module
@@ -1,4 +1,5 @@
 <?php
+
 /**
  * @file
  * Allows administrators to improve security of the website.
@@ -26,568 +27,3 @@ function seckit_permission() {
     ),
   );
 }
-
-/**
- * Implements hook_menu().
- */
-function seckit_menu() {
-  // settings page
-  $items['admin/config/system/seckit'] = array(
-    'title'            => 'Security Kit',
-    'page callback'    => 'drupal_get_form',
-    'page arguments'   => array('seckit_admin_form'),
-    'description'      => 'Configure various options to improve security of your website.',
-    'access arguments' => array('administer seckit'),
-    'file'             => 'includes/seckit.form.inc',
-  );
-  // menu callback for CSP reporting
-  $items['admin/config/system/seckit/csp-report'] = array(
-    'page callback'   => '_seckit_csp_report',
-    'access callback' => TRUE,
-    'type'            => MENU_CALLBACK,
-  );
-  return $items;
-}
-
-/**
- * Implements hook_init().
- */
-function seckit_init() {
-  // get default/set options
-  $options = _seckit_get_options();
-
-  // execute necessary functions
-  if ($options['seckit_csrf']['origin']) {
-    _seckit_origin();
-  }
-  if ($options['seckit_xss']['csp']['checkbox']) {
-    _seckit_csp();
-  }
-  if ($options['seckit_xss']['x_xss']['select']) {
-    _seckit_x_xss($options['seckit_xss']['x_xss']['select']);
-  }
-  if ($options['seckit_xss']['x_content_type']['checkbox']) {
-    _seckit_x_content_type_options();
-  }
-  if ($options['seckit_clickjacking']['x_frame']) {
-    _seckit_x_frame($options['seckit_clickjacking']['x_frame']);
-  }
-  if ($options['seckit_clickjacking']['js_css_noscript']) {
-    _seckit_js_css_noscript();
-  }
-  if ($options['seckit_ssl']['hsts']) {
-    _seckit_hsts();
-  }
-  if ($options['seckit_various']['from_origin']) {
-    _seckit_from_origin();
-  }
-
-  // load jQuery listener
-  if ($_GET['q'] == 'admin/config/system/seckit') {
-    $path = drupal_get_path('module', 'seckit');
-    $listener = "$path/js/seckit.listener.js";
-    drupal_add_js($listener);
-  }
-}
-
-/**
- * Implements hook_boot().
- *
- * When multiple 'Allow-From' values are configured for X-Frame-Options,
- * we dynamically set the header so that it is correct even when pages are
- * served from the page cache.
- *
- * In other circumstances, Drupal does not see this implementation.
- * @see seckit_module_implements_alter().
- */
-function seckit_boot() {
-  $options = _seckit_get_options();
-  if ($options['seckit_clickjacking']['x_frame'] != SECKIT_X_FRAME_ALLOW_FROM) {
-    return;
-  }
-
-  // If this request's Origin is allowed, we specify that value.
-  // If the origin is not allowed, we can use any other value to prevent
-  // the client from framing the page.
-  $allowed = $options['seckit_clickjacking']['x_frame_allow_from'];
-  $origin = !empty($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
-  if (!in_array($origin, $allowed, TRUE)) {
-    $origin = array_pop($allowed);
-  }
-
-  drupal_add_http_header('X-Frame-Options', "Allow-From: $origin");
-}
-
-/**
- * Implements hook_module_implements_alter().
- *
- * The 'Allow-From' field of X-Frame-Options supports a single origin only.
- * http://tools.ietf.org/html/rfc7034#section-2.3.2.3
- *
- * Consequently, when multiple values are configured we must resort to
- * hook_boot() to dynamically set the header to the Origin of the current
- * request, if that is one of the allowed values.
- *
- * Conversely, when we do not require hook_boot(), we unset our
- * implementation, preventing _system_update_bootstrap_status() from
- * registering it, and anything from invoking it.
- *
- * @see seckit_admin_form_submit().
- */
-function seckit_module_implements_alter(&$implementations, $hook) {
-  if ($hook != 'boot') {
-    return;
-  }
-
-  $options = _seckit_get_options(TRUE);
-  if ($options['seckit_clickjacking']['x_frame'] != SECKIT_X_FRAME_ALLOW_FROM
-    || count($options['seckit_clickjacking']['x_frame_allow_from']) <= 1)
-  {
-    // seckit_boot() is not needed.
-    unset($implementations['seckit']);
-    // In this case, _seckit_x_frame() will generate the header
-    // (which will be cacheable), if it is required.
-  }
-}
-
-/**
- * Sends Content Security Policy HTTP headers.
- *
- * Header specifies Content Security Policy (CSP) for a website,
- * which is used to allow/block content from selected sources.
- *
- * Based on specification available at http://www.w3.org/TR/CSP/
- */
-function _seckit_csp() {
-  // get default/set options
-  $options         = _seckit_get_options();
-  $options         = $options['seckit_xss']['csp'];
-  $csp_report_only = $options['report-only'];
-  $csp_default_src = $options['default-src'];
-  $csp_script_src  = $options['script-src'];
-  $csp_object_src  = $options['object-src'];
-  $csp_img_src     = $options['img-src'];
-  $csp_media_src   = $options['media-src'];
-  $csp_style_src   = $options['style-src'];
-  $csp_frame_src   = $options['frame-src'];
-  $csp_font_src    = $options['font-src'];
-  $csp_connect_src = $options['connect-src'];
-  $csp_report_uri  = $options['report-uri'];
-  $csp_policy_uri  = $options['policy-uri'];
-
-  // prepare directives
-  $directives = array();
-
-  // if policy-uri is declared, no other directives are permitted.
-  if ($csp_policy_uri) {
-    $directives = "policy-uri " . base_path() . $csp_policy_uri;
-  }
-  // otherwise prepare directives
-  else {
-    if ($csp_default_src) {
-      $directives[] = "default-src $csp_default_src";
-    }
-    if ($csp_script_src) {
-      $directives[] = "script-src $csp_script_src";
-    }
-    if ($csp_object_src) {
-      $directives[] = "object-src $csp_object_src";
-    }
-    if ($csp_style_src) {
-      $directives[] = "style-src $csp_style_src";
-    }
-    if ($csp_img_src) {
-      $directives[] = "img-src $csp_img_src";
-    }
-    if ($csp_media_src) {
-      $directives[] = "media-src $csp_media_src";
-    }
-    if ($csp_frame_src) {
-      $directives[] = "frame-src $csp_frame_src";
-    }
-    if ($csp_font_src) {
-      $directives[] = "font-src $csp_font_src";
-    }
-    if ($csp_connect_src) {
-      $directives[] = "connect-src $csp_connect_src";
-    }
-    if ($csp_report_uri) {
-      $directives[] = "report-uri " . base_path() . $csp_report_uri;
-    }
-    // merge directives
-    $directives = implode('; ', $directives);
-  }
-
-  // send HTTP response header if directives were prepared
-  if ($directives) {
-    if ($csp_report_only) {
-      // use report-only mode
-      drupal_add_http_header('Content-Security-Policy-Report-Only', $directives); // official name
-      drupal_add_http_header('X-Content-Security-Policy-Report-Only', $directives); // Firefox and IE10
-      drupal_add_http_header('X-WebKit-CSP-Report-Only', $directives); // Chrome and Safari
-    }
-    else {
-      drupal_add_http_header('Content-Security-Policy', $directives); // official name
-      drupal_add_http_header('X-Content-Security-Policy', $directives); // Firefox and IE10
-      drupal_add_http_header('X-WebKit-CSP', $directives); // Chrome and Safari
-    }
-  }
-}
-
-/**
- * Reports CSP violations to watchdog.
- */
-function _seckit_csp_report() {
-  // Only allow POST data with Content-Type application/csp-report
-  // or application/json (the latter to support older user agents).
-  // n.b. The CSP spec (1.0, 1.1) mandates this Content-Type header/value.
-  // n.b. Content-Length is optional, so we don't check it.
-  if (empty($_SERVER['CONTENT_TYPE']) || empty($_SERVER['REQUEST_METHOD'])) {
-    return;
-  }
-  if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
-    return;
-  }
-  $pattern = '~^application/(csp-report|json)\h*(;|$)~';
-  if (!preg_match($pattern, $_SERVER['CONTENT_TYPE'])) {
-    return;
-  }
-
-  // Get and parse report.
-  $reports = file_get_contents('php://input');
-  $reports = json_decode($reports);
-  if (!is_object($reports)) {
-    return;
-  }
-
-  // Log the report data to watchdog.
-  foreach ($reports as $report) {
-    if (!isset($report->{'violated-directive'})) {
-      continue;
-    }
-    $info = array(
-      '@directive'   => $report->{'violated-directive'},
-      '@blocked_uri' => $report->{'blocked-uri'},
-      '@data'        => print_r($report, TRUE),
-    );
-    watchdog('seckit', 'CSP: Directive @directive violated.<br /> Blocked URI: @blocked_uri.<br /> <pre>Data: @data</pre>', $info, WATCHDOG_WARNING);
-  }
-}
-
-/**
- * Sends X-XSS-Protection HTTP header.
- *
- * X-XSS-Protection controls IE8/Safari/Chrome internal XSS filter.
- */
-function _seckit_x_xss($setting) {
-  switch ($setting) {
-    case SECKIT_X_XSS_0:
-      drupal_add_http_header('X-XSS-Protection', '0'); // set X-XSS-Protection header to 0
-      break;
-
-    case SECKIT_X_XSS_1:
-      drupal_add_http_header('X-XSS-Protection', '1; mode=block'); // set X-XSS-Protection header to 1; mode=block
-      break;
-
-    case SECKIT_X_XSS_DISABLE:
-    default: // do nothing
-      break;
-  }
-}
-
-/**
- * Sends X-Content-Type-Options HTTP response header.
- */
-function _seckit_x_content_type_options() {
-  drupal_add_http_header('X-Content-Type-Options', 'nosniff');
-}
-
-/**
- * Aborts HTTP request upon invalid 'Origin' HTTP request header.
- *
- * When included in an HTTP request, the Origin header indicates the origin(s)
- * that caused the user agent to issue the request. This helps to protect
- * against CSRF attacks, as we can abort requests with an unapproved origin.
- *
- * Applies to all HTTP request methods except GET and HEAD.
- *
- * Requests which do not include an 'Origin' header must always be allowed,
- * as (a) not all user-agents support the header, and (b) those that do may
- * include it or omit it at their discretion.
- *
- * Note that (a) will become progressively less of a factor over time --
- * CSRF attacks depend upon convincing a user agent to send a request, and
- * there is no particular motivation for users to prevent their web browsers
- * from sending this header; so as people upgrade to browsers which support
- * 'Origin', its effectiveness increases.
- *
- * Implementation of Origin is based on specification draft available at
- * http://tools.ietf.org/html/draft-abarth-origin-09
- */
-function _seckit_origin() {
-  // Allow requests without an 'Origin' header, or with a 'null' origin.
-  $origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
-  if (!$origin || $origin === 'null') {
-    return;
-  }
-  // Allow command-line requests.
-  // TODO: Should this test be in seckit_init() ?
-  // (i.e. Should this module do *anything* in the case of cli requests?)
-  if (drupal_is_cli()) {
-    return;
-  }
-  // Allow GET and HEAD requests.
-  $method = $_SERVER['REQUEST_METHOD'];
-  if (in_array($method, array('GET', 'HEAD'), TRUE)) {
-    return;
-  }
-  // Allow requests from localhost.
-  if (in_array(ip_address(), array('localhost', '127.0.0.1', '::1'), TRUE)) {
-    return;
-  }
-
-  // Allow requests from whitelisted Origins.
-  global $base_root;
-  $options = _seckit_get_options();
-  $whitelist = explode(',', $options['seckit_csrf']['origin_whitelist']);
-  $whitelist[] = $base_root; // default origin is always allowed
-  if (in_array($origin, $whitelist, TRUE)) {
-    return;
-  }
-
-  // The Origin is invalid, so we deny the request.
-  // Clean the POST data first, as drupal_access_denied() may render a page
-  // with forms which check for their submissions.
-  $_POST = array();
-  drupal_access_denied(); // send 403 response and show Access Denied page
-  $args = array(
-    '@ip'     => ip_address(),
-    '@origin' => $origin,
-  );
-  watchdog('seckit', 'Possible CSRF attack was blocked. IP address: @ip, Origin: @origin.', $args, WATCHDOG_WARNING);
-  drupal_exit(); // abort request
-}
-
-/**
- * Sends X-Frame-Options HTTP header.
- *
- * X-Frame-Options controls should browser show frames or not.
- * More information can be found at initial article about it at
- * http://blogs.msdn.com/ie/archive/2009/01/27/ie8-security-part-vii-clickjacking-defenses.aspx
- *
- * Implementation of X-Frame-Options is based on specification draft availabe at
- * http://tools.ietf.org/html/draft-ietf-websec-x-frame-options-01
- */
-function _seckit_x_frame($setting) {
-  switch ($setting) {
-    case SECKIT_X_FRAME_SAMEORIGIN:
-      drupal_add_http_header('X-Frame-Options', 'SameOrigin'); // set X-Frame-Options to SameOrigin
-      break;
-
-    case SECKIT_X_FRAME_DENY:
-      drupal_add_http_header('X-Frame-Options', 'Deny'); // set X-Frame-Options to Deny
-      break;
-
-    case SECKIT_X_FRAME_ALLOW_FROM:
-      $options = _seckit_get_options();
-      $allowed = $options['seckit_clickjacking']['x_frame_allow_from'];
-      if (count($allowed) == 1) {
-        $value = array_pop($allowed);
-        drupal_add_http_header('X-Frame-Options', "Allow-From: $value");
-      }
-      // If there were multiple values, then seckit_boot() took care of it.
-      break;
-
-    case SECKIT_X_FRAME_DISABLE:
-    default: // do nothing
-      break;
-  }
-}
-
-/**
- * Enables JavaScript + CSS + Noscript Clickjacking defense.
- *
- * Closes inline JavaScript and allows loading of any inline HTML elements.
- * After, it starts new inline JavaScript to avoid breaking syntax.
- * We need it, because Drupal API doesn't allow to init HTML elements in desired sequence.
- */
-function _seckit_js_css_noscript() {
-  drupal_add_js(_seckit_get_js_css_noscript_code(), array('type' => 'inline'));
-}
-
-/**
- * Gets JavaScript and CSS code.
- *
- * @return string
- */
-function _seckit_get_js_css_noscript_code() {
-  $options = _seckit_get_options();
-  $message = filter_xss($options['seckit_clickjacking']['noscript_message']);
-  $path = base_path() . drupal_get_path('module', 'seckit');
-  return <<< EOT
-      // close script tag for SecKit protection
-      //--><!]]>
-      </script>
-      <script type="text/javascript" src="$path/js/seckit.document_write.js"></script>
-      <link type="text/css" rel="stylesheet" id="seckit-clickjacking-no-body" media="all" href="$path/css/seckit.no_body.css" />
-      <!-- stop SecKit protection -->
-      <noscript>
-      <link type="text/css" rel="stylesheet" id="seckit-clickjacking-noscript-tag" media="all" href="$path/css/seckit.noscript_tag.css" />
-      <div id="seckit-noscript-tag">
-        <h1>$message</h1>
-      </div>
-      </noscript>
-      <script type="text/javascript">
-      <!--//--><![CDATA[//><!--
-      // open script tag to avoid syntax errors
-EOT;
-}
-
-/**
- * Sends From-Origin HTTP response header.
- *
- * Implementation is based on specification draft
- * available at http://www.w3.org/TR/from-origin.
- */
-function _seckit_from_origin() {
-  $options = _seckit_get_options();
-  $value = $options['seckit_various']['from_origin_destination'];
-  drupal_add_http_header('From-Origin', $value);
-}
-
-/**
- * Sends Strict-Transport-Security HTTP header
- *
- * HTTP Strict-Transport-Security (HSTS) header prevents eavesdropping and MITM attacks like SSLStrip,
- * forces user-agent to send requests in HTTPS-only mode and convert HTTP links into secure.
- *
- * Implementation of HSTS is based on the specification draft available at
- * http://tools.ietf.org/html/draft-hodges-strict-transport-sec-02
- */
-function _seckit_hsts() {
-  // get default/set options
-  $options = _seckit_get_options();
-  // prepare HSTS header value
-  $max_age = $options['seckit_ssl']['hsts_max_age'];
-  $subdomains = $options['seckit_ssl']['hsts_subdomains'];
-  $header[] = "max-age=$max_age";
-  if ($subdomains) {
-    $header[] = 'includeSubDomains';
-  }
-  $header = implode('; ', $header);
-  // send HSTS header
-  drupal_add_http_header('Strict-Transport-Security', $header);
-}
-
-/**
- * Converts a multi-line configuration option to an array.
- * Sanitises by trimming whitespace, and filtering empty options.
- */
-function _seckit_explode_value($string) {
-  $values = explode("\n", $string);
-  return array_values(array_filter(array_map('trim', $values)));
-}
-
-/**
- * Sets default options.
- *
- * @param boolean $reset
- *   If TRUE then re-generate (and re-cache) the options.
- *
- * @param boolean $alter
- *   Whether to invoke hook_seckit_options_alter().
- *   (Used internally to prevent altered values being used
- *   in the admin settings form.)
- */
-function _seckit_get_options($reset = FALSE, $alter = TRUE) {
-  $result = &drupal_static(__FUNCTION__, array());
-  if ($reset) {
-    $result = array();
-  }
-  elseif ($result) {
-    return $result;
-  }
-
-  // set default options
-  $default['seckit_xss']['csp'] = array(
-    'report-only' => 0,
-    'script-src'  => '',
-    'object-src'  => '',
-    'img-src'     => '',
-    'media-src'   => '',
-    'style-src'   => '',
-    'frame-src'   => '',
-    'font-src'    => '',
-    'connect-src' => '',
-    'policy-uri'  => '',
-  );
-  $default['seckit_csrf'] = array(
-    'origin'           => 1,
-    'origin_whitelist' => '',
-  );
-  $default['seckit_clickjacking'] = array(
-    'js_css_noscript' => 0,
-    'x_frame_allow_from' => '',
-  );
-  $default['seckit_ssl'] = array(
-    'hsts'            => 0,
-    'hsts_subdomains' => 0,
-  );
-  $default['seckit_various'] = array(
-    'from_origin' => 0,
-  );
-  // get variables
-  $result['seckit_xss']          = variable_get('seckit_xss', $default['seckit_xss']);
-  $result['seckit_csrf']         = variable_get('seckit_csrf', $default['seckit_csrf']);
-  $result['seckit_clickjacking'] = variable_get('seckit_clickjacking', $default['seckit_clickjacking']);
-  $result['seckit_ssl']          = variable_get('seckit_ssl', $default['seckit_ssl']);
-  $result['seckit_various']      = variable_get('seckit_various', $default['seckit_various']);
-  // enable Content Security Policy (CSP)
-  if (!isset($result['seckit_xss']['csp']['checkbox'])) {
-    $result['seckit_xss']['csp']['checkbox'] = 0;
-  }
-  // set CSP default-src directive to self
-  if (!isset($result['seckit_xss']['csp']['default-src']) || !$result['seckit_xss']['csp']['default-src']) {
-    $result['seckit_xss']['csp']['default-src'] = "'self'";
-  }
-  // set CSP report-uri directive to menu callback
-  if (!isset($result['seckit_xss']['csp']['report-uri']) || !$result['seckit_xss']['csp']['report-uri']) {
-    $result['seckit_xss']['csp']['report-uri'] = 'admin/config/system/seckit/csp-report';
-  }
-  // set X-XSS-Protection header to disabled (browser default).
-  if (!isset($result['seckit_xss']['x_xss']['select'])) {
-    $result['seckit_xss']['x_xss']['select'] = SECKIT_X_XSS_DISABLE;
-  }
-  // enable X-Content-Type-Options
-  if (!isset($result['seckit_xss']['x_content_type']['checkbox'])) {
-    $result['seckit_xss']['x_content_type']['checkbox'] = 1;
-  }
-  // enable Origin-based protection
-  if (!isset($result['seckit_csrf']['origin'])) {
-    $result['seckit_csrf']['origin'] = 1;
-  }
-  // set X-Frame-Options header to SameOrigin
-  if (!isset($result['seckit_clickjacking']['x_frame'])) {
-    $result['seckit_clickjacking']['x_frame'] = SECKIT_X_FRAME_SAMEORIGIN;
-  }
-  $x_frame_allow_from =& $result['seckit_clickjacking']['x_frame_allow_from'];
-  $x_frame_allow_from = _seckit_explode_value($x_frame_allow_from);
-
-  // set Custom text for disabled JavaScript message
-  if (!isset($result['seckit_clickjacking']['noscript_message'])) {
-    $result['seckit_clickjacking']['noscript_message'] = t('Sorry, you need to enable JavaScript to visit this website.');
-  }
-  // set HSTS max-age to 1000
-  if (!isset($result['seckit_ssl']['hsts_max_age'])) {
-    $result['seckit_ssl']['hsts_max_age'] = 1000;
-  }
-  // set From-Origin to same
-  if (!isset($result['seckit_various']['from_origin_destination'])) {
-    $result['seckit_various']['from_origin_destination'] = 'same';
-  }
-
-  if ($alter) {
-    drupal_alter('seckit_options', $result);
-  }
-  return $result;
-}
diff --git a/seckit.routing.yml b/seckit.routing.yml
new file mode 100644
index 0000000..94645d5
--- /dev/null
+++ b/seckit.routing.yml
@@ -0,0 +1,14 @@
+seckit.settings:
+  path: '/admin/config/system/seckit'
+  defaults:
+    _title: 'Security Kit'
+    _form: '\Drupal\seckit\Form\SettingsForm'
+  requirements:
+    _permission: 'administer seckit'
+seckit.report:
+  path: '/admin/config/system/seckit/csp-report'
+  defaults:
+    _title: ''
+    _content: '\Drupal\seckit\Controller\SeckitExportController::export'
+  requirements:
+    _access: 'TRUE'
diff --git a/seckit.services.yml b/seckit.services.yml
new file mode 100644
index 0000000..888d47a
--- /dev/null
+++ b/seckit.services.yml
@@ -0,0 +1,6 @@
+services:
+  seckit.subscriber:
+    class: Drupal\seckit\EventSubscriber\SecKitEventSubscriber
+    arguments: ['@request']
+    tags:
+      - { name: event_subscriber }
diff --git a/src/Controller/SeckitExportController.php b/src/Controller/SeckitExportController.php
new file mode 100644
index 0000000..9682ca4
--- /dev/null
+++ b/src/Controller/SeckitExportController.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\seckit\Controller\SeckitExportController.
+ */
+namespace Drupal\seckit\Controller;
+/**
+ * Example page controller.
+ */
+class SeckitExportController {
+  /**
+   * Reports CSP violations to watchdog.
+   */
+  public function export() {
+    // Only allow POST data with Content-Type application/csp-report
+    // or application/json (the latter to support older user agents).
+    // n.b. The CSP spec (1.0, 1.1) mandates this Content-Type header/value.
+    // n.b. Content-Length is optional, so we don't check it.
+    if (empty($_SERVER['CONTENT_TYPE']) || empty($_SERVER['REQUEST_METHOD'])) {
+      return;
+    }
+    if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
+      return;
+    }
+    $pattern = '~^application/(csp-report|json)\h*(;|$)~';
+    if (!preg_match($pattern, $_SERVER['CONTENT_TYPE'])) {
+      return;
+    }
+
+    // Get and parse report.
+    $reports = file_get_contents('php://input');
+    $reports = json_decode($reports);
+    if (!is_object($reports)) {
+      return;
+    }
+
+    // Log the report data to watchdog.
+    foreach ($reports as $report) {
+      if (!isset($report->{'violated-directive'})) {
+        continue;
+      }
+      $info = array(
+        '@directive'   => $report->{'violated-directive'},
+        '@blocked_uri' => $report->{'blocked-uri'},
+        '@data'        => print_r($report, TRUE),
+      );
+      watchdog('seckit', 'CSP: Directive @directive violated.<br /> Blocked URI: @blocked_uri.<br /> <pre>Data: @data</pre>', $info, WATCHDOG_WARNING);
+    }
+  }
+}
diff --git a/src/EventSubscriber/SecKitEventSubscriber.php b/src/EventSubscriber/SecKitEventSubscriber.php
new file mode 100644
index 0000000..f29d601
--- /dev/null
+++ b/src/EventSubscriber/SecKitEventSubscriber.php
@@ -0,0 +1,344 @@
+<?php
+
+namespace Drupal\seckit\EventSubscriber;
+
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpKernel\KernelEvents;
+use Symfony\Component\HttpKernel\Event\GetResponseEvent;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Drupal\Component\Utility\Xss;
+
+class SecKitEventSubscriber implements EventSubscriberInterface {
+
+  protected $request;
+  protected $config;
+
+  public function __construct(Request $request) {
+    $this->request = $request;
+    $this->config = \Drupal::config('seckit.settings');
+  }
+
+  public function onKernelRequest(GetResponseEvent $event) {
+    // execute necessary functions
+    if ($this->config->get('seckit_csrf.origin')) {
+      $this->_seckit_origin();
+    }
+    if ($this->config->get('seckit_xss.csp.checkbox')) {
+      $this->_seckit_csp();
+    }
+    if ($this->config->get('seckit_xss.x_xss.select')) {
+      $this->_seckit_x_xss($this->config->get('seckit_xss.x_xss.select'));
+    }
+    if ($this->config->get('seckit_xss.x_content_type.checkbox')) {
+      $this->_seckit_x_content_type_options();
+    }
+    if ($this->config->get('seckit_clickjacking.x_frame')) {
+      $this->_seckit_x_frame($this->config->get('seckit_clickjacking.x_frame'));
+    }
+    if ($this->config->get('seckit_clickjacking.js_css_noscript')) {
+      $this->_seckit_js_css_noscript();
+    }
+    if ($this->config->get('seckit_ssl.hsts')) {
+      $this->_seckit_hsts();
+    }
+    if ($this->config->get('seckit_various.from_origin')) {
+      $this->_seckit_from_origin();
+    }
+  }
+
+  /**
+   * Aborts HTTP request upon invalid 'Origin' HTTP request header.
+   *
+   * When included in an HTTP request, the Origin header indicates the origin(s)
+   * that caused the user agent to issue the request. This helps to protect
+   * against CSRF attacks, as we can abort requests with an unapproved origin.
+   *
+   * Applies to all HTTP request methods except GET and HEAD.
+   *
+   * Requests which do not include an 'Origin' header must always be allowed,
+   * as (a) not all user-agents support the header, and (b) those that do may
+   * include it or omit it at their discretion.
+   *
+   * Note that (a) will become progressively less of a factor over time --
+   * CSRF attacks depend upon convincing a user agent to send a request, and
+   * there is no particular motivation for users to prevent their web browsers
+   * from sending this header; so as people upgrade to browsers which support
+   * 'Origin', its effectiveness increases.
+   *
+   * Implementation of Origin is based on specification draft available at
+   * http://tools.ietf.org/html/draft-abarth-origin-09
+   */
+  public function _seckit_origin() {
+    // Allow requests without an 'Origin' header, or with a 'null' origin.
+    $origin = isset($_SERVER['HTTP_ORIGIN']) ? $_SERVER['HTTP_ORIGIN'] : '';
+    if (!$origin || $origin === 'null') {
+      return;
+    }
+    // Allow command-line requests.
+    // TODO: Should this test be in seckit_init() ?
+    // (i.e. Should this module do *anything* in the case of cli requests?)
+    if (drupal_is_cli()) {
+      return;
+    }
+    // Allow GET and HEAD requests.
+    $method = $this->request->getMethod();
+    if (in_array($method, array('GET', 'HEAD'), TRUE)) {
+      return;
+    }
+    // Allow requests from localhost.
+    if (in_array($this->request->getClientIp(), array('localhost', '127.0.0.1', '::1'), TRUE)) {
+      return;
+    }
+
+    // Allow requests from whitelisted Origins.
+    global $base_root;
+
+    $whitelist = explode(',', $this->config->get('seckit_csrf.origin_whitelist'));
+    $whitelist[] = $base_root; // default origin is always allowed
+    if (in_array($origin, $whitelist, TRUE)) {
+      return;
+    }
+    // The Origin is invalid, so we deny the request.
+    // Clean the POST data first, as drupal_access_denied() may render a page
+    // with forms which check for their submissions.
+    $args = array(
+      '@ip'     => $this->request->getClientIp(),
+      '@origin' => $origin,
+    );
+    $warning = t('Possible CSRF attack was blocked. IP address: @ip, Origin: @origin.', $args);
+    watchdog('seckit', $warning, array(), WATCHDOG_WARNING);
+    // abort request
+    drupal_add_http_header('Status', '403 Forbidden');
+    throw new AccessDeniedHttpException($warning);
+  }
+
+  /**
+   * Sends Content Security Policy HTTP headers.
+   *
+   * Header specifies Content Security Policy (CSP) for a website,
+   * which is used to allow/block content from selected sources.
+   *
+   * Based on specification available at http://www.w3.org/TR/CSP/
+   */
+  public function _seckit_csp() {
+    // Get default/set options.
+    $csp_report_only = $this->config->get('seckit_xss.csp.policy-uri');
+    $csp_default_src = $this->config->get('seckit_xss.csp.default-src');
+    $csp_script_src  = $this->config->get('seckit_xss.csp.script-src');
+    $csp_object_src  = $this->config->get('seckit_xss.csp.object-src');
+    $csp_img_src     = $this->config->get('seckit_xss.csp.img-src');
+    $csp_media_src   = $this->config->get('seckit_xss.csp.media-src');
+    $csp_style_src   = $this->config->get('seckit_xss.csp.style-src');
+    $csp_frame_src   = $this->config->get('seckit_xss.csp.frame-src');
+    $csp_font_src    = $this->config->get('seckit_xss.csp.font-src');
+    $csp_connect_src = $this->config->get('seckit_xss.csp.connect-src');
+    $csp_report_uri  = $this->config->get('seckit_xss.csp.report-uri');
+    $csp_policy_uri  = $this->config->get('seckit_xss.csp.policy-uri');
+    // Prepare directives.
+    $directives = array();
+
+    // If policy-uri is declared, no other directives are permitted.
+    /*if ($csp_report_only) {
+      $directives = "policy-uri " . base_path() . $csp_report_only;
+    }*/
+    // Otherwise prepare directives.
+   // else {
+      if ($csp_default_src) {
+        $directives[] = "default-src $csp_default_src";
+      }
+      if ($csp_script_src) {
+        $directives[] = "script-src $csp_script_src";
+      }
+      if ($csp_object_src) {
+        $directives[] = "object-src $csp_object_src";
+      }
+      if ($csp_style_src) {
+        $directives[] = "style-src $csp_style_src";
+      }
+      if ($csp_img_src) {
+        $directives[] = "img-src $csp_img_src";
+      }
+      if ($csp_media_src) {
+        $directives[] = "media-src $csp_media_src";
+      }
+      if ($csp_frame_src) {
+        $directives[] = "frame-src $csp_frame_src";
+      }
+      if ($csp_font_src) {
+        $directives[] = "font-src $csp_font_src";
+      }
+      if ($csp_connect_src) {
+        $directives[] = "connect-src $csp_connect_src";
+      }
+      if ($csp_report_uri) {
+        $directives[] = "report-uri " . base_path() . $csp_report_uri;
+      }
+      // Merge directives.
+      $directives = implode('; ', $directives);
+   // }
+
+    // send HTTP response header if directives were prepared
+    if ($directives) {
+      if ($csp_report_only) {
+        // use report-only mode
+        drupal_add_http_header('Content-Security-Policy-Report-Only', $directives); // official name
+        drupal_add_http_header('X-Content-Security-Policy-Report-Only', $directives); // Firefox and IE10
+        drupal_add_http_header('X-WebKit-CSP-Report-Only', $directives); // Chrome and Safari
+      }
+      else {
+        drupal_add_http_header('Content-Security-Policy', $directives); // official name
+        drupal_add_http_header('X-Content-Security-Policy', $directives); // Firefox and IE10
+        drupal_add_http_header('X-WebKit-CSP', $directives); // Chrome and Safari
+      }
+    }
+  }
+
+  /**
+   * Sends X-XSS-Protection HTTP header.
+   *
+   * X-XSS-Protection controls IE8/Safari/Chrome internal XSS filter.
+   */
+  public function _seckit_x_xss($setting) {
+    switch ($setting) {
+      case SECKIT_X_XSS_0:
+        drupal_add_http_header('X-XSS-Protection', '0'); // set X-XSS-Protection header to 0
+        break;
+
+      case SECKIT_X_XSS_1:
+        drupal_add_http_header('X-XSS-Protection', '1; mode=block'); // set X-XSS-Protection header to 1; mode=block
+        break;
+
+      case SECKIT_X_XSS_DISABLE:
+      default: // do nothing
+        break;
+    }
+  }
+
+  /**
+   * Sends X-Content-Type-Options HTTP response header.
+   */
+  public function _seckit_x_content_type_options() {
+    drupal_add_http_header('X-Content-Type-Options', 'nosniff');
+  }
+
+  /**
+   * Sends X-Frame-Options HTTP header.
+   *
+   * X-Frame-Options controls should browser show frames or not.
+   * More information can be found at initial article about it at
+   * http://blogs.msdn.com/ie/archive/2009/01/27/ie8-security-part-vii-clickjacking-defenses.aspx
+   *
+   * Implementation of X-Frame-Options is based on specification draft availabe at
+   * http://tools.ietf.org/html/draft-ietf-websec-x-frame-options-01
+   */
+  public function _seckit_x_frame($setting) {
+    switch ($setting) {
+      case SECKIT_X_FRAME_SAMEORIGIN:
+        drupal_add_http_header('X-Frame-Options', 'SameOrigin'); // set X-Frame-Options to SameOrigin
+        break;
+
+      case SECKIT_X_FRAME_DENY:
+        drupal_add_http_header('X-Frame-Options', 'Deny'); // set X-Frame-Options to Deny
+        break;
+
+      case SECKIT_X_FRAME_ALLOW_FROM:
+        $allowed = $this->config->get('seckit_clickjacking.x_frame_allow_from');
+        $allowed = explode(',', $allowed);
+        if (count($allowed) == 1) {
+          $value = array_pop($allowed);
+          drupal_add_http_header('X-Frame-Options', "Allow-From: $value");
+        }
+        // If there were multiple values, then seckit_boot() took care of it.
+        break;
+
+      case SECKIT_X_FRAME_DISABLE:
+      default: // do nothing
+        break;
+    }
+  }
+
+  static function getSubscribedEvents() {
+    $events[KernelEvents::REQUEST][] = array('onKernelRequest', 100);
+    return $events;
+  }
+
+
+  /**
+   * Enables JavaScript + CSS + Noscript Clickjacking defense.
+   *
+   * Closes inline JavaScript and allows loading of any inline HTML elements.
+   * After, it starts new inline JavaScript to avoid breaking syntax.
+   * We need it, because Drupal API doesn't allow to init HTML elements in desired sequence.
+   */
+  public function _seckit_js_css_noscript() {
+    _drupal_add_js($this->_seckit_get_js_css_noscript_code(), array('type' => 'inline'));
+  }
+
+  /**
+   * Gets JavaScript and CSS code.
+   *
+   * @return string
+   */
+  public function _seckit_get_js_css_noscript_code($noscript_message = NULL) {
+    // Allows noscript automated testing.
+    $noscript_message = $noscript_message ?
+      $noscript_message :
+      $this->config->get('seckit_clickjacking.noscript_message');
+
+    $message = Xss::filter($noscript_message);
+    $path = base_path() . drupal_get_path('module', 'seckit');
+    return <<< EOT
+        // close script tag for SecKit protection
+        //--><!]]>
+        </script>
+        <script type="text/javascript" src="$path/js/seckit.document_write.js"></script>
+        <link type="text/css" rel="stylesheet" id="seckit-clickjacking-no-body" media="all" href="$path/css/seckit.no_body.css" />
+        <!-- stop SecKit protection -->
+        <noscript>
+        <link type="text/css" rel="stylesheet" id="seckit-clickjacking-noscript-tag" media="all" href="$path/css/seckit.noscript_tag.css" />
+        <div id="seckit-noscript-tag">
+          <h1>$message</h1>
+        </div>
+        </noscript>
+        <script type="text/javascript">
+        <!--//--><![CDATA[//><!--
+        // open script tag to avoid syntax errors
+EOT;
+  }
+
+  /**
+   * Sends Strict-Transport-Security HTTP header
+   *
+   * HTTP Strict-Transport-Security (HSTS) header prevents eavesdropping and MITM attacks like SSLStrip,
+   * forces user-agent to send requests in HTTPS-only mode and convert HTTP links into secure.
+   *
+   * Implementation of HSTS is based on the specification draft available at
+   * http://tools.ietf.org/html/draft-hodges-strict-transport-sec-02
+   */
+  public function _seckit_hsts() {
+    // prepare HSTS header value
+    $max_age = $this->config->get('seckit_ssl.hsts_max_age');
+    $subdomains = $this->config->get('seckit_ssl.hsts_subdomains');
+    $header[] = "max-age=$max_age";
+    if ($subdomains) {
+      $header[] = 'includeSubDomains';
+    }
+    $header = implode('; ', $header);
+    // send HSTS header
+    drupal_add_http_header('Strict-Transport-Security', $header);
+  }
+
+
+  /**
+   * Sends From-Origin HTTP response header.
+   *
+   * Implementation is based on specification draft
+   * available at http://www.w3.org/TR/from-origin.
+   */
+  public function _seckit_from_origin() {
+    $value = $this->config->get('seckit_various.from_origin_destination');
+    drupal_add_http_header('From-Origin', $value);
+  }
+}
diff --git a/src/Form/SettingsForm.php b/src/Form/SettingsForm.php
new file mode 100644
index 0000000..8d0979a
--- /dev/null
+++ b/src/Form/SettingsForm.php
@@ -0,0 +1,476 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\seckit\Form\SettingsForm.
+ */
+
+namespace Drupal\seckit\Form;
+use Drupal\Core\Form\ConfigFormBase;
+/**
+ * Implements a form to collect security check configuration.
+ */
+class SettingsForm extends ConfigFormBase {
+ /**
+   * {@inheritdoc}.
+   */
+  public function getFormId() {
+    return 'seckit_settings_form';
+  }
+  /**
+   * {@inheritdoc}.
+   */
+  public function buildForm(array $form, array &$form_state) {
+    $module_path = drupal_get_path('module', 'seckit');
+    $form['#attached']['js'][] = $module_path . '/js/seckit.listener.js';
+
+    $config = $this->config('seckit.settings');
+    // main description
+    $args['!browserscope'] =  t('<a href="@url">Browserscope</a>', array('@url' => url('http://www.browserscope.org/?category=security')));
+    $form['seckit_description'] = array(
+      '#type' => 'item',
+      '#description' => t('This module provides your website with various options to mitigate risks of common web application vulnerabilities like Cross-site Scripting, Cross-site Request Forgery and Clickjacking. It also has some options to improve your SSL/TLS security and fixes Drupal 6 core Upload module issue leading to an easy exploitation of an old Internet Explorer MIME sniffer HTML injection vulnerability. Note that some security features are not supported by all browsers. You may find this out at !browserscope.', $args),
+    );
+
+    // main fieldset for XSS
+    $form['seckit_xss'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Cross-site Scripting'),
+      '#collapsible' => TRUE,
+      '#tree' => TRUE,
+      '#description' => t('Configure levels and various techniques of protection from cross-site scripting attacks'),
+    );
+
+    // fieldset for Content Security Policy (CSP)
+
+    $args['!wiki'] = t('<a href="@url">Mozilla Wiki</a>', array('@url' => url('https://wiki.mozilla.org/Security/CSP')));
+    $description = t('Content Security Policy is a policy framework that allows to specify trustworthy sources of content and to restrict its capabilities. You may read more about it at !wiki.', $args);
+    $form['seckit_xss']['csp'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Content Security Policy'),
+      '#collapsible' => TRUE,
+      '#tree' => TRUE,
+      '#description' => $description,
+    );
+    // CSP enable/disable
+    $form['seckit_xss']['csp']['checkbox'] = array(
+      '#type' => 'checkbox',
+      '#default_value' => $config->get('seckit_xss.csp.checkbox'),
+      '#title' => t('Send HTTP response header'),
+      '#return_value' => 1,
+      '#description' => t('Send Content-Security-Policy (official), X-Content-Security-Policy (supported by Mozilla Firefox and IE10) and X-WebKit-CSP (supported by Google Chrome and Safari) HTTP response headers with the list of Content Security Policy directives.'),
+    );
+    // CSP report-only mode
+    $form['seckit_xss']['csp']['report-only'] = array(
+      '#type' => 'checkbox',
+      '#default_value' => $config->get('seckit_xss.csp.report-only'),
+      '#title' => t('Report Only'),
+      '#return_value' => 1,
+      '#description' => t('Use Content Security Policy in report-only mode. In this case, violations of policies will only be reported, not blocked. Use this while configuring policies. Reports are logged to watchdog.'),
+    );
+    // CSP description
+    $items = array(
+      "'none' - block content from any source",
+      "'self' - allow content only from your domain",
+      "'unsafe-inline' - allow specific inline content (note, that it is supported by a subset of directives)",
+      "'unsafe-eval' - allow a set of string-to-code API which is restricted by default (supported by script-src directive)"
+    );
+    $args['!keywords'] = $this->_getItemsList($items);
+    $items = array('* - load content from any source', '*.example.com - load content from example.com and all its subdomains', 'example.com:* - load content from example.com via any port.  Otherwise, it will use your website default port');
+    $args['!wildcards'] =  $this->_getItemsList($items);
+    $args['!spec'] = t('<a href="@url">specification page</a>', array('@url' => url('http://www.w3.org/TR/CSP/')));
+    $description = t("Set up security policy for different types of content. Don't use www prefix. Keywords are: !keywords Wildcards (*) are allowed: !wildcards More information is available at !spec.", $args);
+    $form['seckit_xss']['csp']['description'] = array(
+      '#type' => 'item',
+      '#title' => t('Directives'),
+      '#description' => $description,
+    );
+    // CSP default-src directive
+    $form['seckit_xss']['csp']['default-src'] = array(
+      '#type' => 'textfield',
+      '#maxlength'=> 1024,
+      '#default_value' => $config->get('seckit_xss.csp.default-src'),
+      '#title' => 'default-src',
+      '#description' => t("Specify security policy for all types of content, which are not specified further (frame-ancestors excepted). Default is 'self'."),
+    );
+    // CSP script-src directive
+    $form['seckit_xss']['csp']['script-src'] = array(
+      '#type' => 'textfield',
+      '#maxlength'=> 1024,
+      '#default_value' => $config->get('seckit_xss.csp.script-src'),
+      '#title' => 'script-src',
+      '#description' => t('Specify trustworthy sources for &lt;script&gt; elements.'),
+    );
+    // CSP object-src directive
+    $form['seckit_xss']['csp']['object-src'] = array(
+      '#type' => 'textfield',
+      '#maxlength'=> 1024,
+      '#default_value' => $config->get('seckit_xss.csp.object-src'),
+      '#title' => 'object-src',
+      '#description' => t('Specify trustworthy sources for &lt;object&gt;, &lt;embed&gt; and &lt;applet&gt; elements.'),
+    );
+    // CSP style-src directive
+    $form['seckit_xss']['csp']['style-src'] = array(
+      '#type' => 'textfield',
+      '#maxlength'=> 1024,
+      '#default_value' => $config->get('seckit_xss.csp.style-src'),
+      '#title' => 'style-src',
+      '#description' => t('Specify trustworthy sources for stylesheets. Note, that inline stylesheets and style attributes of HTML elements are allowed.'),
+    );
+    // CSP img-src directive
+    $form['seckit_xss']['csp']['img-src'] = array(
+      '#type' => 'textfield',
+      '#maxlength'=> 1024,
+      '#default_value' => $config->get('seckit_xss.csp.img-src'),
+      '#title' => 'img-src',
+      '#description' => t('Specify trustworthy sources for &lt;img&gt; elements.'),
+    );
+    // CSP media-src directive
+    $form['seckit_xss']['csp']['media-src'] = array(
+      '#type' => 'textfield',
+      '#maxlength'=> 1024,
+      '#default_value' => $config->get('seckit_xss.csp.media-src'),
+      '#title' => 'media-src',
+      '#description' => t('Specify trustworthy sources for &lt;audio&gt; and &lt;video&gt; elements.'),
+    );
+    // CSP frame-src directive
+    $form['seckit_xss']['csp']['frame-src'] = array(
+      '#type' => 'textfield',
+      '#maxlength'=> 1024,
+      '#default_value' => $config->get('seckit_xss.csp.frame-src'),
+      '#title' => 'frame-src',
+      '#description' => t('Specify trustworthy sources for &lt;iframe&gt; and &lt;frame&gt; elements.'),
+    );
+    // CSP font-src directive
+    $form['seckit_xss']['csp']['font-src'] = array(
+      '#type' => 'textfield',
+      '#maxlength'=> 1024,
+      '#default_value' => $config->get('seckit_xss.csp.font-src'),
+      '#title' => 'font-src',
+      '#description' => t('Specify trustworthy sources for @font-src CSS loads.'),
+    );
+    // CSP connect-src directive
+    $form['seckit_xss']['csp']['connect-src'] = array(
+      '#type' => 'textfield',
+      '#maxlength'=> 1024,
+      '#default_value' => $config->get('seckit_xss.csp.connect-src'),
+      '#title' => 'connect-src',
+      '#description' => t('Specify trustworthy sources for XMLHttpRequest, WebSocket and EventSource connections.'),
+    );
+    // CSP report-uri directive
+    $form['seckit_xss']['csp']['report-uri'] = array(
+      '#type' => 'textfield',
+      '#maxlength'=> 1024,
+      '#default_value' =>  $config->get('seckit_xss.csp.report-uri'),
+      '#title' => 'report-uri',
+      '#description' => t('Specify a URL (relative to the Drupal root) to which user-agents will report CSP violations. Use the default value, unless you have set up an alternative handler for these reports. Defaults to <code>admin/config/system/seckit/csp-report</code> which logs the report data in watchdog.'),
+    );
+    // CSP policy-uri directive
+    $form['seckit_xss']['csp']['policy-uri'] = array(
+      '#type' => 'textfield',
+      '#maxlength'=> 1024,
+      '#default_value' => $config->get('seckit_xss.csp.policy-uri'),
+      '#title' => 'policy-uri',
+      '#description' => t("Specify a URL (relative to the Drupal root) for a file containing the (entire) policy. <strong>All other directives will be omitted</strong> by Security Kit, as <code>policy-uri</code> may only be defined in the <em>absence</em> of other policy definitions in the <code>X-Content-Security-Policy</code> HTTP header. The MIME type for this URI <strong>must</strong> be <code>text/x-content-security-policy</code>, otherwise user-agents will enforce the policy <code>allow 'none'</code>  instead."),
+    );
+
+    // fieldset for X-XSS-Protection
+    $form['seckit_xss']['x_xss'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('X-XSS-Protection'),
+      '#collapsible' => TRUE,
+      '#tree' => TRUE,
+      '#description' => t('X-XSS-Protection HTTP response header controls Microsoft Internet Explorer, Google Chrome and Apple Safari internal XSS filters.'),
+    );
+    // options for X-XSS-Protection
+    $x_xss_protection_options = array(
+      SECKIT_X_XSS_DISABLE => t($config->get('seckit_xss.x_xss.seckit_x_xss_option_disable')),
+      SECKIT_X_XSS_0 => $config->get('seckit_xss.x_xss.seckit_x_xss_option_0'),
+      SECKIT_X_XSS_1 => $config->get('seckit_xss.x_xss.seckit_x_xss_option_1'),
+    );
+    // configure X-XSS-Protection
+    $link = t('<a href="@url">IE\'s XSS filter security flaws in past</a>', array('@url' => url('http://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities')));
+    $items = array('Disabled - XSS filter will work in default mode. Enabled by default', '0 - XSS filter will be disabled for a website. It may be useful because of ' . $link, '1; mode=block - XSS filter will be left enabled, but it will block entire page instead of modifying dangerous content');
+    $args['!values'] =  $this->_getItemsList($items);
+    $form['seckit_xss']['x_xss']['select'] = array(
+      '#type' => 'select',
+      '#title' => t('Configure'),
+      '#options' => $x_xss_protection_options,
+      '#default_value' => $config->get('seckit_xss.x_xss.select'),
+      '#description' => t('!values', $args),
+    );
+
+    // fieldset for X-Content-Type-Options
+    $args['!link'] = t('<a href="@url">MSDN article</a>', array('@url' => url('http://blogs.msdn.com/b/ie/archive/2010/10/26/mime-handling-changes-in-internet-explorer.aspx')));
+    $form['seckit_xss']['x_content_type'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('X-Content-Type-Options'),
+      '#collapsible' => TRUE,
+      '#tree' => TRUE,
+      '#description' => t('X-Content-Type-Options HTTP response header prevents browser from upsniffing content and serving files with inappropriate MIME type. More information is available at !link.', $args),
+    );
+    // enable/disable X-Content-Type-Options
+    $form['seckit_xss']['x_content_type']['checkbox'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Send HTTP response header'),
+      '#default_value' => $config->get('seckit_xss.x_content_type.checkbox'),
+      '#description' => t('Enable X-Content-Type-Options: nosniff HTTP response header.'),
+    );
+
+    // main fieldset for CSRF
+    $form['seckit_csrf'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Cross-site Request Forgery'),
+      '#tree' => TRUE,
+      '#collapsible' => TRUE,
+      '#description' => t('Configure levels and various techniques of protection from cross-site request forgery attacks'),
+    );
+
+    // enable/disable Origin
+    $form['seckit_csrf']['origin'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('HTTP Origin'),
+      '#default_value' => $config->get('seckit_csrf.origin'),
+      '#description' => t('Check Origin HTTP request header.'),
+    );
+    // Origin whitelist
+    $description = t('Comma separated list of trustworthy sources. Do not enter your website URL - it is automatically added. Syntax of the source is: [protocol] :// [host] : [port] . E.g, http://example.com, https://example.com, https://www.example.com, http://www.example.com:8080');
+    $form['seckit_csrf']['origin_whitelist'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Allow requests from'),
+      '#default_value' => $config->get('seckit_csrf.origin_whitelist'),
+      '#size' => 90,
+      '#description' => $description,
+    );
+
+    // main fieldset for Clickjacking
+    $form['seckit_clickjacking'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Clickjacking'),
+      '#collapsible' => TRUE,
+      '#tree' => TRUE,
+      '#description' => t('Configure levels and various techniques of protection from Clickjacking/UI Redressing attacks'),
+    );
+
+    // options for X-Frame-Options
+    $x_frame_options = array(
+      SECKIT_X_FRAME_DISABLE => t('Disabled'),
+      SECKIT_X_FRAME_SAMEORIGIN => 'SameOrigin',
+      SECKIT_X_FRAME_DENY => 'Deny',
+      SECKIT_X_FRAME_ALLOW_FROM => 'Allow-From',
+    );
+    // configure X-Frame-Options
+    $items = array('Disabled - turn off X-Frame-Options', 'SameOrigin - browser allows all the attempts of framing website within its domain. Enabled by default', 'Deny - browser rejects any attempt of framing website', 'Allow-From - browser allows framing website only from specified source');
+    $args['!values'] = $this->_getItemsList($items);
+    $args['!msdn'] =  t('<a href="@url">MSDN article</a>', array('@url' => url('http://blogs.msdn.com/b/ie/archive/2009/01/27/ie8-security-part-vii-clickjacking-defenses.aspx')));
+    $args['!spec'] = t('<a href="@url">specification</a>', array('@url' => url('http://tools.ietf.org/html/draft-ietf-websec-x-frame-options-01')));
+    $description = t("X-Frame-Options HTTP response header controls browser's policy of frame rendering. Possible values: !values You may read more about it at !msdn or !spec.", $args);
+    $form['seckit_clickjacking']['x_frame'] = array(
+      '#type' => 'select',
+      '#title' => t('X-Frame-Options'),
+      '#options' => $x_frame_options,
+      '#default_value' => $config->get('seckit_clickjacking.x_frame'),
+      '#description' => $description,
+    );
+
+    // Origin value for "Allow-From" option.
+    $form['seckit_clickjacking']['x_frame_allow_from'] = array(
+      '#type' => 'textarea',
+      '#title' => t('Allow-From'),
+      '#default_value' => $config->get('seckit_clickjacking.x_frame_allow_from'),
+      '#description' => t('Origin URIs (as specified by RFC 6454) for the "X-Frame-Options: Allow-From" value. One per line. Example, http://domain.com'),
+    );
+
+    // enable/disable JS + CSS + Noscript protection
+    $args['!link'] = t('<a href="@url">sirdarckcat</a>', array('@url' => url('http://www.sirdarckcat.net/')));
+    $args['%js'] = t('seckit.document_write.js');
+    $args['%write'] = t('document.write()');
+    $args['%stop'] = t('stop SecKit protection');
+    $args['%css'] = t('seckit.no_body.css');
+    $args['%display'] = t('display: none');
+    $description = t('Enable protection via JavaScript, CSS and Noscript tag. This is the most efficient Clickjacking prevention technique. If webiste is not being framed, %js starts commenting with %write and stops when reaches %stop. Thus %css, which sets body display to none, is ignored. If particularly this JavaScript file is being blocked (with XSS filter of Internet Explorer 8 or Safari), %css sets %display to body. If JavaScript is disabled within browser, it shows a special message. Credits for this trick go to !link.', $args);
+    $form['seckit_clickjacking']['js_css_noscript'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Enable JavaScript + CSS + Noscript protection'),
+      '#return_value' => 1,
+      '#default_value' => $config->get('seckit_clickjacking.js_css_noscript'),
+      '#description' => $description,
+    );
+
+    // custom text for "disabled JavaScript" message
+    $form['seckit_clickjacking']['noscript_message'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Custom text for disabled JavaScript message'),
+      '#default_value' => $config->get('seckit_clickjacking.noscript_message'),
+      '#description' => t('This message will be shown to user when JavaScript is disabled or unsupported in his browser. Default is "Sorry, you need to enable JavaScript to visit this website."'),
+    );
+
+    // main fieldset for SSL/TLS
+    $form['seckit_ssl'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('SSL/TLS'),
+      '#collapsible' => TRUE,
+      '#tree' => TRUE,
+      '#description' => t('Configure various techniques to improve security of SSL/TLS'),
+    );
+    // enable/disable HTTP Strict Transport Security (HSTS)
+    $args['!wiki'] = t('<a href="@url">Wikipedia</a>', array('@url' => url('http://en.wikipedia.org/wiki/HTTP_Strict_Transport_Security')));
+    $form['seckit_ssl']['hsts'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('HTTP Strict Transport Security'),
+      '#description' => t('Enable Strict-Transport-Security HTTP response header. HTTP Strict Transport Security (HSTS) header is proposed to prevent eavesdropping and man-in-the-middle attacks like SSLStrip, when a single non-HTTPS request is enough for credential theft or hijacking. It forces browser to connect to the server in HTTPS-mode only and automatically convert HTTP links into secure before sending request. !wiki has more information about HSTS', $args),
+      '#default_value' => $config->get('seckit_ssl.hsts'),
+    );
+    // HSTS max-age directive
+    $form['seckit_ssl']['hsts_max_age'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Max-Age'),
+      '#description' => t('Specify Max-Age value in seconds. It sets period when user-agent should remember receipt of this header field from this server. Default is 1000.'),
+      '#default_value' => $config->get('seckit_ssl.hsts_max_age'),
+    );
+    // STS includeSubDomains directive
+    $form['seckit_ssl']['hsts_subdomains'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('Include Subdomains'),
+      '#description' => t('Force HTTP Strict Transport Security for all subdomains. If enabled, HSTS policy will be applied for all subdomains, otherwise only for the main domain.'),
+      '#default_value' => $config->get('seckit_ssl.hsts_subdomains'),
+    );
+
+    // main fieldset for various
+    $form['seckit_various'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Various'),
+      '#collapsible' => TRUE,
+      '#tree' => TRUE,
+      '#description' => t('Configure various unsorted security enhancements'),
+    );
+
+    // enable/disable From-Origin
+    $args['!spec'] = t('<a href="@url">specification</a>', array('@url' => url('http://www.w3.org/TR/from-origin/')));
+    $form['seckit_various']['from_origin'] = array(
+      '#type' => 'checkbox',
+      '#title' => t('From-Origin'),
+      '#default_value' => $config->get('seckit_various.from_origin'),
+      '#description' => t('Enable From-Origin HTTP response header. This forces user-agent to retrieve embedded content from your site only to listed destination. More information is available at !spec page.', $args),
+    );
+    // From-Origin destination
+    $items = array('same - allow loading of content only from your site. Default value.', 'serialized origin - address of trustworthy destination. For example, http://example.com, https://example.com, https://www.example.com, http://www.example.com:8080');
+    $args['!items'] = $this->_getItemsList($items);
+    $form['seckit_various']['from_origin_destination'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Allow loading content to'),
+      '#default_value' => $config->get('seckit_various.from_origin_destination'),
+      '#size' => 90,
+      '#description' => t('Trustworthy destination. Possible variants are: !items', $args),
+    );
+    return parent::buildForm($form, $form_state);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function validateForm(array &$form, array &$form_state) {
+    // if From-Origin is enabled, it should be explicitly set
+    $from_origin_enable = $form_state['values']['seckit_various']['from_origin'];
+    $from_origin_destination = $form_state['values']['seckit_various']['from_origin_destination'];
+    if (($from_origin_enable == 1) && (!$from_origin_destination)) {
+      form_error($form['seckit_various']['from_origin_destination'], $form_state, t('You have to set up trustworthy destination for From-Origin HTTP response header. Default is same.'));
+    }
+    // if X-Frame-Options is set to Allow-From, it should be explicitly set
+    $x_frame_value = $form_state['values']['seckit_clickjacking']['x_frame'];
+    if ($x_frame_value == SECKIT_X_FRAME_ALLOW_FROM) {
+      $x_frame_allow_from = $form_state['values']['seckit_clickjacking']['x_frame_allow_from'];
+      if (!$this->_seckit_explode_value($x_frame_allow_from)) {
+        form_error($form['seckit_clickjacking']['x_frame_allow_from'], $form_state, t('You must specify a trusted Origin for the Allow-From value of the X-Frame-Options HTTP response header.'));
+      }
+    }
+    // if HTTP Strict Transport Security is enabled, max-age must be specified.
+    // HSTS max-age should only contain digits.
+    $hsts_enable = $form_state['values']['seckit_ssl']['hsts'];
+    $hsts_max_age = $form_state['values']['seckit_ssl']['hsts_max_age'];
+    if (($hsts_enable == 1) && (!$hsts_max_age)) {
+      form_error($form['seckit_ssl']['hsts_max_age'], $form_state, t('You have to set up Max-Age value for HTTP Strict Transport Security. Default is 1000.'));
+    }
+    if (preg_match('/[^0-9]/', $hsts_max_age)) {
+      form_error($form['seckit_ssl']['hsts_max_age'], $form_state, t('Only digits are allowed in HTTP Strict Transport Security Max-Age field.'));
+    }
+    // if JS + CSS + Noscript Clickjacking protection is enabled,
+    // custom text for disabled JS must be specified
+    $js_css_noscript_enable = $form_state['values']['seckit_clickjacking']['js_css_noscript'];
+    $noscript_message = $form_state['values']['seckit_clickjacking']['noscript_message'];
+    if (($js_css_noscript_enable == 1) && (!$noscript_message)) {
+      form_error($form['seckit_clickjacking']['noscript_message'], $form_state, t('You have to set up Custom text for disabled JavaScript message when JS + CSS + Noscript protection is enabled.'));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function submitForm(array &$form, array &$form_state) {
+    $list = [];
+    $this->buildAttributeList($list, $form_state['values']);
+    $config = $this->config('seckit.settings');
+
+    foreach ($list as $key => $value) {
+      $config->set($key, $value);
+    }
+
+    $config->save();
+
+    $from_origin_enable = $form_state['values']['seckit_various']['from_origin'];
+    $x_content_type_options_enable = $form_state['values']['seckit_xss']['x_content_type']['checkbox'];
+    $file_system = file_default_scheme();
+    if ($from_origin_enable && ($file_system == 'public')) {
+      $msg = 'From-Origin HTTP response header will not be served for files because of public file system. It is recommended to enable private file system to ensure provided by From-Origin security.';
+      drupal_set_message($msg, 'warning');
+    }
+    if ($x_content_type_options_enable && ($file_system == 'public')) {
+      $msg = 'X-Content-Type-Options HTTP response header will not be served for files because of public file system. It is recommended to enable private file system to ensure provided by X-Content-Type-Options security.';
+      drupal_set_message($msg, 'warning');
+    }
+
+    return parent::submitForm($form, $form_state);
+  }
+
+  /**
+   * Build a list from given items.
+   */
+  public function _getItemsList($items) {
+    $list = array(
+      '#theme' => 'item_list',
+      '#items' => $items,
+    );
+    return drupal_render($list);
+  }
+
+  /**
+   * Build the configuration form value list.
+   */
+  protected function buildAttributeList(
+    array &$list = [],
+    array $rawAttributes = [],
+    $currentName = '')
+  {
+    foreach ($rawAttributes as $key => $rawAttribute) {
+      $name = $currentName ? $currentName . '.' . $key:$key;
+      if (in_array($name,['op','form_id','form_token','form_build_id','submit'])){
+        continue;
+      }
+      if (is_array($rawAttribute)) {
+        $this->buildAttributeList($list, $rawAttribute, $name);
+      } else {
+         $list[$name] = $rawAttribute;
+      }
+    }
+  }
+
+  /**
+   * Converts a multi-line configuration option to an array.
+   * Sanitises by trimming whitespace, and filtering empty options.
+   */
+  protected function _seckit_explode_value($string) {
+    $values = explode("\n", $string);
+    return array_values(array_filter(array_map('trim', $values)));
+  }
+
+}
\ No newline at end of file
diff --git a/src/Tests/SecKitCSPCaseTest.php b/src/Tests/SecKitCSPCaseTest.php
new file mode 100644
index 0000000..b863d91
--- /dev/null
+++ b/src/Tests/SecKitCSPCaseTest.php
@@ -0,0 +1,126 @@
+<?php
+/**
+ * @file
+ * Tests 2 for Security Kit module.
+ */
+namespace Drupal\seckit\Tests;
+use Drupal\simpletest\WebTestBase;
+use Drupal\seckit\EventSubscriber\SecKitEventSubscriber;
+/**
+ * Functional tests for Security Kit.
+ */
+class SecKitCSPCaseTest extends WebTestBase {
+  /**
+   * Admin user for tests
+   * @var object
+   */
+  private $admin;
+  public static $modules = array('seckit');
+  /**
+   * Implements getInfo().
+   * @see DrupalWebTestCase::getInfo()
+   */
+  public static function getInfo() {
+    return array(
+      'name' => t('Security Kit CSP functionality'),
+      'description' => t('Tests CSP functionality and settings page of Security Kit module.'),
+      'group' => t('Security Kit'),
+    );
+  }
+
+  /**
+   * Implements setUp().
+   * @see DrupalWebTestCase::setUp()
+   */
+  public function setUp() {
+    parent::setUp();
+    $this->admin = $this->drupalCreateUser(array('administer seckit'));
+    $this->drupalLogin($this->admin);
+  }
+
+  /**
+   * Tests Content Security Policy with all enabled directives.
+   */
+  public function testCSPHasAllDirectives() {
+    $form = array(
+      'seckit_xss[csp][checkbox]'    => TRUE,
+      'seckit_xss[csp][default-src]' => '*',
+      'seckit_xss[csp][script-src]'  => '*',
+      'seckit_xss[csp][object-src]'  => '*',
+      'seckit_xss[csp][style-src]'   => '*',
+      'seckit_xss[csp][img-src]'     => '*',
+      'seckit_xss[csp][media-src]'   => '*',
+      'seckit_xss[csp][frame-src]'   => '*',
+      'seckit_xss[csp][font-src]'    => '*',
+      'seckit_xss[csp][connect-src]' => '*',
+      'seckit_xss[csp][report-uri]'  => 'admin/config/system/seckit/csp-report',
+    );
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $expected = 'default-src *; script-src *; object-src *; style-src *; img-src *; media-src *; frame-src *; font-src *; connect-src *; report-uri /admin/config/system/seckit/csp-report';
+    $this->assertEqual($expected, $this->drupalGetHeader('Content-Security-Policy'),
+      t('Content-Security-Policy has all the directves (Official).'));
+    $this->assertEqual($expected, $this->drupalGetHeader('X-Content-Security-Policy'),
+      t('X-Content-Security-Policy has all the directves (Mozilla and IE10).'));
+    $this->assertEqual($expected, $this->drupalGetHeader('X-WebKit-CSP'),
+      t('X-WebKit-CSP has all the directves (Chrome and Safari).'));
+  }
+
+  /**
+   * Tests Content Security Policy with policy-uri directive.
+   * In this case, only policy-uri directive should be present.
+   *//*
+  public function testCSPPolicyUriDirectiveOnly() {
+    $form = array(
+      'seckit_xss[csp][checkbox]'    => TRUE,
+      'seckit_xss[csp][default-src]' => '*',
+      'seckit_xss[csp][script-src]'  => '*',
+      'seckit_xss[csp][object-src]'  => '*',
+      'seckit_xss[csp][style-src]'   => '*',
+      'seckit_xss[csp][img-src]'     => '*',
+      'seckit_xss[csp][media-src]'   => '*',
+      'seckit_xss[csp][frame-src]'   => '*',
+      'seckit_xss[csp][font-src]'    => '*',
+      'seckit_xss[csp][connect-src]' => '*',
+      'seckit_xss[csp][report-uri]'  => 'admin/config/system/seckit/csp-report',
+      'seckit_xss[csp][policy-uri]'  => 'http://mysite.com/csp.xml',
+    );
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $expected = 'policy-uri http://mysite.com/csp.xml';
+    $this->assertEqual($expected, $this->drupalGetHeader('Content-Security-Policy'),
+      t('Content-Security-Policy has only policy-uri (Official).'));
+    $this->assertEqual($expected, $this->drupalGetHeader('X-Content-Security-Policy'),
+      t('X-Content-Security-Policy has only policy-uri (Mozilla and IE10).'));
+    $this->assertEqual($expected, $this->drupalGetHeader('X-WebKit-CSP'),
+      t('X-WebKit-CSP has only policy-uri(Chrome and Safari).'));
+  }
+*/
+  /**
+   * Tests Content Security Policy with all directives empty.
+   * In this case, we should revert back to default values.
+   */
+  public function testCSPAllDirectivesEmpty() {
+    $form = array(
+      'seckit_xss[csp][checkbox]'    => TRUE,
+      'seckit_xss[csp][default-src]' => 'self',
+      'seckit_xss[csp][script-src]'  => '',
+      'seckit_xss[csp][object-src]'  => '',
+      'seckit_xss[csp][img-src]'     => '',
+      'seckit_xss[csp][media-src]'   => '',
+      'seckit_xss[csp][style-src]'   => '',
+      'seckit_xss[csp][frame-src]'   => '',
+      'seckit_xss[csp][font-src]'    => '',
+      'seckit_xss[csp][connect-src]' => '',
+      'seckit_xss[csp][report-uri]'  => 'admin/config/system/seckit/csp-report',
+      'seckit_xss[csp][policy-uri]'  => '',
+    );
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $expected = "default-src self; report-uri /admin/config/system/seckit/csp-report";
+    $this->assertEqual($expected, $this->drupalGetHeader('Content-Security-Policy'),
+      t('Content-Security-Policy has default directive (Official).'));
+    $this->assertEqual($expected, $this->drupalGetHeader('X-Content-Security-Policy'),
+      t('X-Content-Security-Policy has default directive (Mozilla and IE10).'));
+    $this->assertEqual($expected, $this->drupalGetHeader('X-WebKit-CSP'),
+      t('X-WebKit-CSP has default directive (Chrome and Safari).'));
+  }
+
+}
diff --git a/src/Tests/SecKitTestCaseTest.php b/src/Tests/SecKitTestCaseTest.php
new file mode 100644
index 0000000..ef5c55a
--- /dev/null
+++ b/src/Tests/SecKitTestCaseTest.php
@@ -0,0 +1,349 @@
+<?php
+/**
+ * @file
+ * Tests for Security Kit module.
+ */
+namespace Drupal\seckit\Tests;
+use Drupal\simpletest\WebTestBase;
+use Drupal\seckit\EventSubscriber\SecKitEventSubscriber;
+/**
+ * Functional tests for Security Kit.
+ */
+class SecKitTestCaseTest extends WebTestBase {
+  /**
+   * Admin user for tests
+   * @var object
+   */
+  private $admin;
+  public static $modules = array('seckit');
+  /**
+   * Implements getInfo().
+   * @see DrupalWebTestCase::getInfo()
+   */
+  public static function getInfo() {
+    return array(
+      'name' => t('Security Kit functionality'),
+      'description' => t('Tests functionality and settings page of Security Kit module.'),
+      'group' => t('Security Kit'),
+    );
+  }
+
+  /**
+   * Implements setUp().
+   * @see DrupalWebTestCase::setUp()
+   */
+  public function setUp() {
+    parent::setUp();
+    $this->admin = $this->drupalCreateUser(array('administer seckit'));
+    $this->drupalLogin($this->admin);
+  }
+
+  /**
+   * Tests disabled Content Security Policy.
+   */
+  public function testDisabledCSP() {
+    $form['seckit_xss[csp][checkbox]'] = FALSE;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertFalse($this->drupalGetHeader('Content-Security-Policy'),
+      t('Content Security Policy is disabled (Official).'));
+    $this->assertFalse($this->drupalGetHeader('X-Content-Security-Policy'),
+      t('Content Security Policy is disabled (Mozilla and IE10).'));
+    $this->assertFalse($this->drupalGetHeader('X-WebKit-CSP'),
+      t('Content Security Policy is disabled (Chrome and Safari).'));
+  }
+
+  /**
+   * Tests Content Security Policy with all enabled directives.
+   */
+  public function testCSPHasAllDirectives() {
+    $form = array(
+      'seckit_xss[csp][checkbox]'    => TRUE,
+      'seckit_xss[csp][default-src]' => '*',
+      'seckit_xss[csp][script-src]'  => '*',
+      'seckit_xss[csp][object-src]'  => '*',
+      'seckit_xss[csp][style-src]'   => '*',
+      'seckit_xss[csp][img-src]'     => '*',
+      'seckit_xss[csp][media-src]'   => '*',
+      'seckit_xss[csp][frame-src]'   => '*',
+      'seckit_xss[csp][font-src]'    => '*',
+      'seckit_xss[csp][connect-src]' => '*',
+      'seckit_xss[csp][report-uri]'  => 'admin/config/system/seckit/csp-report',
+    );
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $expected = 'default-src *; script-src *; object-src *; style-src *; img-src *; media-src *; frame-src *; font-src *; connect-src *; report-uri /admin/config/system/seckit/csp-report';
+    $this->assertEqual($expected, $this->drupalGetHeader('Content-Security-Policy'),
+      t('Content-Security-Policy has all the directives (Official).'));
+    $this->assertEqual($expected, $this->drupalGetHeader('X-Content-Security-Policy'),
+      t('X-Content-Security-Policy has all the directives (Mozilla and IE10).'));
+    $this->assertEqual($expected, $this->drupalGetHeader('X-WebKit-CSP'),
+      t('X-WebKit-CSP has all the directives (Chrome and Safari).'));
+  }
+
+  /**
+   * Tests Content Security Policy with policy-uri directive.
+   * In this case, only policy-uri directive should be present.
+   *//*
+  public function testCSPPolicyUriDirectiveOnly() {
+    $form = array(
+      'seckit_xss[csp][checkbox]'    => TRUE,
+      'seckit_xss[csp][default-src]' => '*',
+      'seckit_xss[csp][script-src]'  => '*',
+      'seckit_xss[csp][object-src]'  => '*',
+      'seckit_xss[csp][style-src]'   => '*',
+      'seckit_xss[csp][img-src]'     => '*',
+      'seckit_xss[csp][media-src]'   => '*',
+      'seckit_xss[csp][frame-src]'   => '*',
+      'seckit_xss[csp][font-src]'    => '*',
+      'seckit_xss[csp][connect-src]' => '*',
+      'seckit_xss[csp][report-uri]'  => 'admin/config/system/seckit/csp-report',
+      'seckit_xss[csp][policy-uri]'  => 'http://mysite.com/csp.xml',
+    );
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $expected = 'policy-uri http://mysite.com/csp.xml';
+    $this->assertEqual($expected, $this->drupalGetHeader('Content-Security-Policy'),
+      t('Content-Security-Policy has only policy-uri (Official).'));
+    $this->assertEqual($expected, $this->drupalGetHeader('X-Content-Security-Policy'),
+      t('X-Content-Security-Policy has only policy-uri (Mozilla and IE10).'));
+    $this->assertEqual($expected, $this->drupalGetHeader('X-WebKit-CSP'),
+      t('X-WebKit-CSP has only policy-uri(Chrome and Safari).'));
+  }*/
+
+  /**
+   * Tests Content Security Policy with all directives empty.
+   * In this case, we should revert back to default values.
+   */
+  public function testCSPAllDirectivesEmpty() {
+    $form = array(
+      'seckit_xss[csp][checkbox]'    => TRUE,
+      'seckit_xss[csp][default-src]' => 'self',
+      'seckit_xss[csp][script-src]'  => '',
+      'seckit_xss[csp][object-src]'  => '',
+      'seckit_xss[csp][img-src]'     => '',
+      'seckit_xss[csp][media-src]'   => '',
+      'seckit_xss[csp][style-src]'   => '',
+      'seckit_xss[csp][frame-src]'   => '',
+      'seckit_xss[csp][font-src]'    => '',
+      'seckit_xss[csp][connect-src]' => '',
+      'seckit_xss[csp][report-uri]'  => 'admin/config/system/seckit/csp-report',
+      'seckit_xss[csp][policy-uri]'  => '',
+    );
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $expected = "default-src self; report-uri /admin/config/system/seckit/csp-report";
+    $this->assertEqual($expected, $this->drupalGetHeader('Content-Security-Policy'),
+      t('Content-Security-Policy has default directive (Official).'));
+    $this->assertEqual($expected, $this->drupalGetHeader('X-Content-Security-Policy'),
+      t('X-Content-Security-Policy has default directive (Mozilla and IE10).'));
+    $this->assertEqual($expected, $this->drupalGetHeader('X-WebKit-CSP'),
+      t('X-WebKit-CSP has default directive (Chrome and Safari).'));
+  }
+
+  /**
+   * Tests Content Security Policy in report-only mode.
+   *//*
+  public function testReportOnlyCSP() {
+    $form['seckit_xss[csp][checkbox]'] = TRUE;
+    $form['seckit_xss[csp][report-only]'] = TRUE;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertTrue($this->drupalGetHeader('Content-Security-Policy-Report-Only'),
+      t('Content Security Policy is in report-only mode (Official).'));
+    $this->assertTrue($this->drupalGetHeader('X-Content-Security-Policy-Report-Only'),
+      t('Content Security Policy is in report-only mode (Mozilla and IE10).'));
+    $this->assertTrue($this->drupalGetHeader('X-WebKit-CSP-Report-Only'),
+      t('Content Security Policy is in report-only mode (Chrome and Safari).'));
+  }
+*/
+  /**
+   * Tests disabled X-XSS-Protection HTTP response header.
+   */
+  public function testXXSSProtectionIsDisabled() {
+    $form['seckit_xss[x_xss][select]'] = SECKIT_X_XSS_DISABLE;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertFalse($this->drupalGetHeader('X-XSS-Protection'),
+      t('X-XSS-Protection is disabled.'));
+  }
+
+  /**
+   * Tests set to 0 X-XSS-Protection HTTP response header.
+   */
+  public function testXXSSProtectionIs0() {
+    $form['seckit_xss[x_xss][select]'] = SECKIT_X_XSS_0;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertEqual(0, $this->drupalGetHeader('X-XSS-Protection'),
+      t('X-XSS-Protection is set to 0.'));
+  }
+
+  /**
+   * Tests set to 1; mode=block X-XSS-Protection HTTP response header.
+   */
+  public function testXXSSProtectionIs1() {
+    $form['seckit_xss[x_xss][select]'] = SECKIT_X_XSS_1;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertEqual('1; mode=block', $this->drupalGetHeader('X-XSS-Protection'),
+      t('X-XSS-Protection is set to 1; mode=block.'));
+  }
+
+  /**
+   * Tests disabled X-Content-Type-Options HTTP response header.
+   */
+  public function testDisabledXContentTypeOptions() {
+    $form['seckit_xss[x_content_type][checkbox]'] = FALSE;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertFalse($this->drupalGetHeader('X-Content-Type-Options'),
+      t('X-Content-Type-Options is disabled.'));
+  }
+
+  /**
+   * Tests enabled X-Content-Type-Options HTTP response header.
+   */
+  public function testEnabledXContentTypeOptions() {
+    $form['seckit_xss[x_content_type][checkbox]'] = TRUE;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertEqual('nosniff', $this->drupalGetHeader('X-Content-Type-Options'),
+      t('X-Content-Type-Options is enabled and set to nosniff.'));
+  }
+
+  /**
+   * Tests HTTP Origin allows requests from the site.
+   */
+  public function testOriginAllowsSite() {
+    global $base_url;
+    $form['seckit_csrf[origin]'] = TRUE;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'),
+      array(), array('Origin: ' . $base_url));
+    $this->assertResponse(200,
+      t('Request is allowed.'));
+  }
+
+  /**
+   * Tests HTTP Origin allows requests from the specified source.
+   */
+  public function testOriginAllowsSpecifiedSource() {
+    $form = array(
+      'seckit_csrf[origin]' => TRUE,
+      'seckit_csrf[origin_whitelist]' => 'http://www.example.com',
+    );
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'),
+      array(), array('Origin: http://www.example.com'));
+    $this->assertResponse(200,
+      t('Whitelisted request is allowed.'));
+  }
+
+  /**
+   * Tests HTTP Origin denies request.
+   */
+  public function testOriginDeny() {
+    $form['seckit_csrf[origin]'] = TRUE;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'),
+      array(), array('Origin: http://www.example.com'));
+    $this->assertEqual(array(), $_POST,
+      t('POST is empty.'));
+    $this->assertResponse('403',
+      t('Request is denied.'));
+  }
+
+  /**
+   * Tests disabled X-Frame-Options HTTP response header.
+   */
+  public function testXFrameOptionsIsDisabled() {
+    $form['seckit_clickjacking[x_frame]'] = SECKIT_X_FRAME_DISABLE;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertFalse($this->drupalGetHeader('X-Frame-Options'),
+      t('X-Frame-Options is disabled.'));
+  }
+
+  /**
+   * Tests set to SameOrigin X-Frame-Options HTTP response header.
+   */
+  public function testXFrameOptionsIsSameOrigin() {
+    $form['seckit_clickjacking[x_frame]'] = SECKIT_X_FRAME_SAMEORIGIN;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertEqual('SameOrigin', $this->drupalGetHeader('X-Frame-Options'),
+      t('X-Frame-Options is set to SameOrigin.'));
+  }
+
+  /**
+   * Tests set to Deny X-Frame-Options HTTP response header.
+   */
+  public function testXFrameOptionsIsDeny() {
+    $form['seckit_clickjacking[x_frame]'] = SECKIT_X_FRAME_DENY;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertEqual('Deny', $this->drupalGetHeader('X-Frame-Options'),
+      t('X-Frame-Options is set to Deny.'));
+  }
+
+  /**
+   * Tests set to Allow-From X-Frame-Options HTTP response header.
+   */
+  public function testXFrameOptionsIsAllowFrom() {
+    $form['seckit_clickjacking[x_frame]'] = SECKIT_X_FRAME_ALLOW_FROM;
+    $form['seckit_clickjacking[x_frame_allow_from]'] = 'http://www.google.com';
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertEqual('Allow-From: http://www.google.com', $this->drupalGetHeader('X-Frame-Options'),
+      t('X-Frame-Options is set to Allow-From.'));
+  }
+
+  /**
+   * Tests JS + CSS + Noscript protection.
+   */
+  public function testJSCSSNoscript() {
+    $form['seckit_clickjacking[js_css_noscript]'] = TRUE;
+    $form['seckit_clickjacking[noscript_message]'] = 'Sorry, your JavaScript is disabled.';
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $config = \Drupal::config('seckit.settings');
+    $no_script_message = $config->get('seckit_clickjacking.noscript_message');
+    $code = SecKitEventSubscriber::_seckit_get_js_css_noscript_code($no_script_message);
+    $this->assertRaw($code,
+      t('JavaScript + CSS + Noscript protection is loaded.'));
+  }
+
+  /**
+   * Tests disabled HTTP Strict Transport Security.
+   */
+  public function testDisabledHSTS() {
+    $form['seckit_ssl[hsts]'] = FALSE;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertFalse($this->drupalGetHeader('Strict-Transport-Security'),
+      t('HTTP Strict Transport Security is disabled.'));
+  }
+
+  /**
+   * Tests HTTP Strict Transport Security has all directives.
+   */
+  public function testHSTSAllDirectves() {
+    $form = array(
+      'seckit_ssl[hsts]' => TRUE,
+      'seckit_ssl[hsts_max_age]' => 1000,
+      'seckit_ssl[hsts_subdomains]' => 1,
+    );
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $expected = 'max-age=1000; includeSubDomains';
+    $this->assertEqual($expected, $this->drupalGetHeader('Strict-Transport-Security'),
+      t('HTTP Strict Transport Security has all the directives.'));
+  }
+
+  /**
+   * Tests disabled From-Origin.
+   */
+  public function testDisabledFromOrigin() {
+    $form['seckit_various[from_origin]'] = FALSE;
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertFalse($this->drupalGetHeader('From-Origin'),
+      t('From-Origin is disabled.'));
+  }
+
+  /**
+   * Tests enabled From-Origin.
+   */
+  public function testEnabledFromOrigin() {
+    $form = array(
+      'seckit_various[from_origin]' => TRUE,
+      'seckit_various[from_origin_destination]' => 'same',
+    );
+    $this->drupalPostForm('admin/config/system/seckit', $form, t('Save configuration'));
+    $this->assertEqual('same', $this->drupalGetHeader('From-Origin'),
+      t('From-Origin is enabled and set to same.'));
+  }
+}
