tcell_agent 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +4 -0
- data/README.md +43 -0
- data/Rakefile +7 -0
- data/bin/tcell_agent +171 -0
- data/config/initializers/authlogic_auth.rb +51 -0
- data/config/initializers/devise_auth.rb +167 -0
- data/config/initializers/init.rb +8 -0
- data/lib/tcell_agent.rb +33 -0
- data/lib/tcell_agent/agent.rb +79 -0
- data/lib/tcell_agent/agent/event_processor.rb +133 -0
- data/lib/tcell_agent/agent/policy_manager.rb +138 -0
- data/lib/tcell_agent/agent/policy_types.rb +42 -0
- data/lib/tcell_agent/agent/static_agent.rb +22 -0
- data/lib/tcell_agent/api.rb +101 -0
- data/lib/tcell_agent/appsensor.rb +42 -0
- data/lib/tcell_agent/appsensor/cmdi.rb +32 -0
- data/lib/tcell_agent/appsensor/path_traversal.rb +33 -0
- data/lib/tcell_agent/appsensor/sqli.rb +55 -0
- data/lib/tcell_agent/appsensor/xss.rb +40 -0
- data/lib/tcell_agent/authlogic.rb +26 -0
- data/lib/tcell_agent/configuration.rb +148 -0
- data/lib/tcell_agent/dataloss.rb +0 -0
- data/lib/tcell_agent/devise.rb +83 -0
- data/lib/tcell_agent/instrumentation.rb +44 -0
- data/lib/tcell_agent/logger.rb +46 -0
- data/lib/tcell_agent/policies/add_script_tag_policy.rb +47 -0
- data/lib/tcell_agent/policies/appsensor_policy.rb +76 -0
- data/lib/tcell_agent/policies/clickjacking_policy.rb +113 -0
- data/lib/tcell_agent/policies/content_security_policy.rb +119 -0
- data/lib/tcell_agent/policies/dataloss_policy.rb +175 -0
- data/lib/tcell_agent/policies/honeytokens_policy.rb +67 -0
- data/lib/tcell_agent/policies/http_redirect_policy.rb +84 -0
- data/lib/tcell_agent/policies/http_tx_policy.rb +60 -0
- data/lib/tcell_agent/policies/login_fraud_policy.rb +42 -0
- data/lib/tcell_agent/policies/secure_headers_policy.rb +64 -0
- data/lib/tcell_agent/rails.rb +146 -0
- data/lib/tcell_agent/rails/devise.rb +0 -0
- data/lib/tcell_agent/rails/dlp.rb +204 -0
- data/lib/tcell_agent/rails/middleware/body_filter_middleware.rb +69 -0
- data/lib/tcell_agent/rails/middleware/context_middleware.rb +50 -0
- data/lib/tcell_agent/rails/middleware/global_middleware.rb +53 -0
- data/lib/tcell_agent/rails/middleware/headers_middleware.rb +176 -0
- data/lib/tcell_agent/rails/routes.rb +130 -0
- data/lib/tcell_agent/rails/settings_reporter.rb +40 -0
- data/lib/tcell_agent/sensor_events/app_config.rb +16 -0
- data/lib/tcell_agent/sensor_events/app_sensor.rb +240 -0
- data/lib/tcell_agent/sensor_events/dlp.rb +58 -0
- data/lib/tcell_agent/sensor_events/honeytokens.rb +16 -0
- data/lib/tcell_agent/sensor_events/login_fraud.rb +43 -0
- data/lib/tcell_agent/sensor_events/metrics.rb +24 -0
- data/lib/tcell_agent/sensor_events/sensor.rb +85 -0
- data/lib/tcell_agent/sensor_events/server_agent.rb +101 -0
- data/lib/tcell_agent/sensor_events/util/redirect_utils.rb +22 -0
- data/lib/tcell_agent/sensor_events/util/sanitizer_utilities.rb +153 -0
- data/lib/tcell_agent/sensor_events/util/utils.rb +21 -0
- data/lib/tcell_agent/sinatra.rb +41 -0
- data/lib/tcell_agent/start_background_thread.rb +63 -0
- data/lib/tcell_agent/userinfo.rb +8 -0
- data/lib/tcell_agent/utils/queue_with_timeout.rb +60 -0
- data/lib/tcell_agent/version.rb +5 -0
- data/spec/controllers/application_controller.rb +12 -0
- data/spec/lib/tcell_agent/api/api_spec.rb +36 -0
- data/spec/lib/tcell_agent/appsensor_spec.rb +66 -0
- data/spec/lib/tcell_agent/policies/add_script_tag_policy_spec.rb +37 -0
- data/spec/lib/tcell_agent/policies/appsensor_policy_spec.rb +40 -0
- data/spec/lib/tcell_agent/policies/clickjacking_policy_spec.rb +71 -0
- data/spec/lib/tcell_agent/policies/content_security_policy_spec.rb +71 -0
- data/spec/lib/tcell_agent/policies/dataloss_policy_spec.rb +88 -0
- data/spec/lib/tcell_agent/policies/honeytokens_policy_spec.rb +22 -0
- data/spec/lib/tcell_agent/policies/http_redirect_policy_spec.rb +62 -0
- data/spec/lib/tcell_agent/policies/http_tx_policy_spec.rb +22 -0
- data/spec/lib/tcell_agent/policies/login_policy_spec.rb +42 -0
- data/spec/lib/tcell_agent/policies/secure_headers_policy_spec.rb +67 -0
- data/spec/lib/tcell_agent/rails/middleware/global_middleware_spec.rb +187 -0
- data/spec/lib/tcell_agent/rails_spec.rb +57 -0
- data/spec/lib/tcell_agent/sensor_events/dlp_spec.rb +14 -0
- data/spec/lib/tcell_agent/sensor_events/util/redirect_utils_spec.rb +25 -0
- data/spec/lib/tcell_agent/sensor_events/util/sanitizer_utilities_spec.rb +57 -0
- data/spec/lib/tcell_agent_spec.rb +22 -0
- data/spec/resources/normal_config.json +13 -0
- data/spec/spec_helper.rb +4 -0
- data/tcell_agent.gemspec +29 -0
- metadata +249 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# See the file "LICENSE" for the full license governing this code.
|
|
2
|
+
|
|
3
|
+
require 'logger'
|
|
4
|
+
require 'cgi'
|
|
5
|
+
require 'uri'
|
|
6
|
+
require 'openssl'
|
|
7
|
+
|
|
8
|
+
module TCellAgent
|
|
9
|
+
module SensorEvents
|
|
10
|
+
module Util
|
|
11
|
+
def self.jhash(str)
|
|
12
|
+
str.each_char.reduce(0) do |result, char|
|
|
13
|
+
[((result << 5) - result) + char.ord].pack('L').unpack('l').first
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
def self.calculateRouteId(method, path, params=nil)
|
|
17
|
+
jhash("#{method}|#{path}")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# See the file "LICENSE" for the full license governing this code.
|
|
2
|
+
|
|
3
|
+
require 'sinatra/base'
|
|
4
|
+
require 'sinatra'
|
|
5
|
+
require 'tcell_agent/agent'
|
|
6
|
+
require 'tcell_agent/instrumentation'
|
|
7
|
+
|
|
8
|
+
module TCellAgent
|
|
9
|
+
class Sinatra::Response
|
|
10
|
+
include Sinatra
|
|
11
|
+
alias_method :original_finish, :finish
|
|
12
|
+
def finish
|
|
13
|
+
status, headers, response = original_finish
|
|
14
|
+
|
|
15
|
+
TCellAgent::Instrumentation.safe_block("Setting CSP Headers") {
|
|
16
|
+
content_security_policy = TCellAgent.policy(TCellAgent::PolicyTypes::CSP)
|
|
17
|
+
if content_security_policy
|
|
18
|
+
content_security_policy.each(
|
|
19
|
+
nil,
|
|
20
|
+
nil,
|
|
21
|
+
nil) do | header_pair |
|
|
22
|
+
headers[header_pair["name"]] = header_pair["value"]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
TCellAgent::Instrumentation.safe_block("Setting Secure Headers") {
|
|
28
|
+
secure_headers_policy = TCellAgent.policy(TCellAgent::PolicyTypes::SecureHeaders)
|
|
29
|
+
if secure_headers_policy
|
|
30
|
+
secure_headers_policy.headers.each do | secure_header |
|
|
31
|
+
headers[secure_header.name] = secure_header.value
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
[status, headers, response]
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# See the file "LICENSE" for the full license governing this code.
|
|
2
|
+
|
|
3
|
+
require 'tcell_agent/logger'
|
|
4
|
+
require 'tcell_agent/agent'
|
|
5
|
+
require 'tcell_agent/configuration'
|
|
6
|
+
|
|
7
|
+
agent = ::TCellAgent::Agent.new(Process.pid)
|
|
8
|
+
TCellAgent.thread_agent = agent
|
|
9
|
+
|
|
10
|
+
# creates a fork and pipes a string from parent to child
|
|
11
|
+
if File.basename($0) != 'rake'
|
|
12
|
+
if (File.basename($0) == 'rails' &&
|
|
13
|
+
((defined?(Thin) && (Rack::Handler.default == Rack::Handler::Thin)) ||
|
|
14
|
+
(defined?(WEBrick) && (Rack::Handler.default == Rack::Handler::WEBrick))))
|
|
15
|
+
TCellAgent.logger.debug("Initializing background thread: Thin")
|
|
16
|
+
begin
|
|
17
|
+
TCellAgent.thread_agent = agent
|
|
18
|
+
agent.start
|
|
19
|
+
rescue Exception => e
|
|
20
|
+
TCellAgent.logger.error("Could not start worker.", e.message)
|
|
21
|
+
end
|
|
22
|
+
elsif defined?(Puma) && defined?(Puma.cli_config) && Puma.cli_config.options[:workers] > 1
|
|
23
|
+
agent.start_event_processor(false)
|
|
24
|
+
# preload app
|
|
25
|
+
TCellAgent.logger.debug("Initializing background thread: Puma Preload")
|
|
26
|
+
puma_worker_start = Proc.new do
|
|
27
|
+
begin
|
|
28
|
+
agent = TCellAgent::Agent.new(Process.pid)
|
|
29
|
+
TCellAgent.thread_agent = agent
|
|
30
|
+
agent.start
|
|
31
|
+
rescue Exception => e
|
|
32
|
+
TCellAgent.logger.error("Could not start worker.", e.message)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
Puma.cli_config.options[:before_worker_boot].push(puma_worker_start)
|
|
36
|
+
elsif defined?(Unicorn) && Unicorn::HttpServer::LISTENERS.length == 0
|
|
37
|
+
agent.start_event_processor(false)
|
|
38
|
+
TCellAgent.logger.debug("Initializing background thread: Unicorn Preload")
|
|
39
|
+
class Unicorn::HttpServer
|
|
40
|
+
alias old_init_worker_process init_worker_process
|
|
41
|
+
def init_worker_process(work)
|
|
42
|
+
begin
|
|
43
|
+
agent = TCellAgent::Agent.new(Process.pid)
|
|
44
|
+
TCellAgent.thread_agent = agent
|
|
45
|
+
agent.start
|
|
46
|
+
rescue Exception => e
|
|
47
|
+
TCellAgent.logger.error("Could not start worker.", e.message)
|
|
48
|
+
end
|
|
49
|
+
return old_init_worker_process(work)
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
else
|
|
53
|
+
TCellAgent.logger.debug("Initializing background thread (no-preload).")
|
|
54
|
+
begin
|
|
55
|
+
TCellAgent.thread_agent = agent
|
|
56
|
+
agent.start
|
|
57
|
+
rescue Exception => e
|
|
58
|
+
TCellAgent.logger.error("Could not start worker.", e.message)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# See the file "LICENSE" for the full license governing this code.
|
|
2
|
+
|
|
3
|
+
require "tcell_agent/logger"
|
|
4
|
+
require 'thread'
|
|
5
|
+
require 'logger'
|
|
6
|
+
|
|
7
|
+
module TCellAgent
|
|
8
|
+
class QueueWithTimeout
|
|
9
|
+
def initialize
|
|
10
|
+
@mutex = Mutex.new
|
|
11
|
+
@queue = []
|
|
12
|
+
@response_time_table = {}
|
|
13
|
+
@recieved = ConditionVariable.new
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def <<(x)
|
|
17
|
+
@mutex.synchronize do
|
|
18
|
+
@queue << x
|
|
19
|
+
@recieved.signal
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
def add_response_time(route_id, response_time)
|
|
23
|
+
@mutex.synchronize do
|
|
24
|
+
if (route_id == nil || route_id == "")
|
|
25
|
+
route_id = "?"
|
|
26
|
+
end
|
|
27
|
+
@response_time_table[route_id] = @response_time_table.fetch(route_id,{})
|
|
28
|
+
@response_time_table[route_id]["c"] = @response_time_table[route_id].fetch("c",0) + 1
|
|
29
|
+
@response_time_table[route_id]["mx"] = [@response_time_table[route_id].fetch("mx",0), response_time].max
|
|
30
|
+
@response_time_table[route_id]["mn"] = [@response_time_table[route_id].fetch("mn",response_time), response_time].min
|
|
31
|
+
@response_time_table[route_id]["t"] = ((@response_time_table[route_id].fetch("t",0)*(@response_time_table[route_id]["c"]-1)) + response_time) / @response_time_table[route_id]["c"]
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
def length
|
|
35
|
+
return @queue.length
|
|
36
|
+
end
|
|
37
|
+
def get_response_time_table
|
|
38
|
+
return @response_time_table
|
|
39
|
+
end
|
|
40
|
+
def reset_response_time_table
|
|
41
|
+
@mutex.synchronize do
|
|
42
|
+
@response_time_table = {}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
def pop(non_block = false)
|
|
46
|
+
pop_with_timeout(non_block ? 0 : nil)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def pop_with_timeout(timeout = nil)
|
|
50
|
+
@mutex.synchronize do
|
|
51
|
+
if @queue.empty?
|
|
52
|
+
@recieved.wait(@mutex, timeout) if timeout != 0
|
|
53
|
+
#if we're still empty after the timeout, raise exception
|
|
54
|
+
raise ThreadError, "queue empty" if @queue.empty?
|
|
55
|
+
end
|
|
56
|
+
@queue.shift
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
describe 'GET /' do
|
|
2
|
+
context 'Get homepage' do
|
|
3
|
+
it 'Adds CSP Headers' do
|
|
4
|
+
|
|
5
|
+
user = create(:user)
|
|
6
|
+
|
|
7
|
+
post :create, session: { email: user.email, password: 'invalid' }
|
|
8
|
+
|
|
9
|
+
expect(response).to render_template(:new)
|
|
10
|
+
expect(flash[:notice]).to match(/^Email and password do not match/)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'addressable/template'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
module TCellAgent
|
|
6
|
+
class TCellApi
|
|
7
|
+
describe "successful POST on /user/create" do
|
|
8
|
+
it "should redirect to dashboard" do
|
|
9
|
+
tapi = TCellApi.new
|
|
10
|
+
TCellAgent.configuration.app_id = "test-appid"
|
|
11
|
+
TCellAgent.configuration.api_key = "test-apikey"
|
|
12
|
+
|
|
13
|
+
def checkreq(req)
|
|
14
|
+
return '{"result":{"csp-headers":{"app_id":"testapp-Becwu","policy_id":' \
|
|
15
|
+
'"acf60560-4e76-11e5-874c-7d71d425b275","headers":[{"name":"Content-Security-Policy-Report-Only",' \
|
|
16
|
+
'"value":"font-src \'none\'; script-src \'self\'; reflected-xss block; ' \
|
|
17
|
+
'style-src \'self\'; connect-src' \
|
|
18
|
+
' \'none\'" ,"report-uri":"http://localhost:3000/csp/cab5e750e66d614bd46fd07a7078db1e74b4f427b2a135b2c96eca684a642707"}]}}}'
|
|
19
|
+
end
|
|
20
|
+
uri_template =
|
|
21
|
+
Addressable::Template.new "https://api.tcell.io/api/v1/app/{app}/update"
|
|
22
|
+
stub_request(:any, uri_template).
|
|
23
|
+
to_return(lambda { |request| {
|
|
24
|
+
:body => checkreq(request), :status => 200,
|
|
25
|
+
:headers => { 'Content-Tyoe' => 'application/json' }
|
|
26
|
+
} })
|
|
27
|
+
|
|
28
|
+
# to_return(:body => resbody,
|
|
29
|
+
result = tapi.pollAPI
|
|
30
|
+
TCellAgent.configuration.app_id = nil
|
|
31
|
+
TCellAgent.configuration.api_key = nil
|
|
32
|
+
expect(result["csp-headers"]["app_id"]).to eq("testapp-Becwu")
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module TCellAgent
|
|
4
|
+
describe AppSensor do
|
|
5
|
+
|
|
6
|
+
context "Safe String" do
|
|
7
|
+
it "Tests Generally Safe Strings" do
|
|
8
|
+
expect(AppSensor.generallySafe("abc def")).to eq(true)
|
|
9
|
+
expect(AppSensor.generallySafe("abc d\">ef")).to eq(false)
|
|
10
|
+
expect(AppSensor.generallySafe("abc \0>ef")).to eq(false)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
context "XSS Detection Test" do
|
|
14
|
+
it "Tests Standard XSS Probes" do
|
|
15
|
+
expect(AppSensor.isXss("abc def")).to eq(false)
|
|
16
|
+
expect(AppSensor.isXss("O'Reilly")).to eq(false)
|
|
17
|
+
|
|
18
|
+
expect(AppSensor.isXss("abc\"><script>")).to eq(true)
|
|
19
|
+
expect(AppSensor.isXss("<script>")).to eq(true)
|
|
20
|
+
expect(AppSensor.isXss("O'><img src='x' onerror='alert(1)'>Reilly")).to eq(true)
|
|
21
|
+
expect(AppSensor.isXss("O'><img/src='x' onerror='alert(1)'>Reilly")).to eq(true)
|
|
22
|
+
expect(AppSensor.isXss("\"><script>alert(/XSSPOSED/);</script>")).to eq(true)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
context "SQLi Detection Test" do
|
|
26
|
+
it "Tests Standard XSS Probes" do
|
|
27
|
+
expect(AppSensor.isSqli("abc def")).to eq(false)
|
|
28
|
+
expect(AppSensor.isSqli("555--")).to eq(false)
|
|
29
|
+
expect(AppSensor.isSqli("555--666")).to eq(false)
|
|
30
|
+
expect(AppSensor.isSqli("I should order by friday")).to eq(false)
|
|
31
|
+
expect(AppSensor.isSqli('b<img src="a"><script>alert(1)</script>')).to eq(false)
|
|
32
|
+
|
|
33
|
+
expect(AppSensor.isSqli("a\" OR \"5\"= \"5")).to eq(true)
|
|
34
|
+
expect(AppSensor.isSqli("a' OR '5'= '5")).to eq(true)
|
|
35
|
+
expect(AppSensor.isSqli("a';--")).to eq(true)
|
|
36
|
+
expect(AppSensor.isSqli("a'--")).to eq(true)
|
|
37
|
+
#expect(AppSensor.isSqli("4 OR 3=3--")).to eq(true)
|
|
38
|
+
expect(AppSensor.isSqli("10 OrDeR By 10--")).to eq(true)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
context "Cmd Injection Test" do
|
|
42
|
+
it "Tests for null character" do
|
|
43
|
+
expect(AppSensor.isCmdi("bob.txt echo 'hi'")).to eq(false)
|
|
44
|
+
expect(AppSensor.isCmdi("bob.txt; echo 'hi'")).to eq(true)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
context "Path Traversal Test" do
|
|
48
|
+
it "Tests for path traversal" do
|
|
49
|
+
expect(AppSensor.isPathTraversal("bob.txt echo 'hi'")).to eq(false)
|
|
50
|
+
expect(AppSensor.isPathTraversal("3/.5")).to eq(false)
|
|
51
|
+
expect(AppSensor.isPathTraversal("../../../test.config")).to eq(true)
|
|
52
|
+
expect(AppSensor.isPathTraversal("/etc/passwd")).to eq(true)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
context "String Characters Test" do
|
|
56
|
+
it "Tests for null character" do
|
|
57
|
+
expect(AppSensor.containsReturnChars("abc def")).to eq(false)
|
|
58
|
+
expect(AppSensor.containsReturnChars("abc\x0adef")).to eq(true)
|
|
59
|
+
expect(AppSensor.containsReturnChars("abc\x0a\x0ddef")).to eq(true)
|
|
60
|
+
expect(AppSensor.containsReturnChars("abc\x0ddef")).to eq(true)
|
|
61
|
+
expect(AppSensor.containsReturnChars("abc\x00 def")).to eq(false)
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module TCellAgent
|
|
4
|
+
module Policies
|
|
5
|
+
describe AddScriptTagPolicy do
|
|
6
|
+
policy_json_empty = {
|
|
7
|
+
"policy_id"=>"01a1",
|
|
8
|
+
"data"=>{
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
policy_json_one = {
|
|
13
|
+
"policy_id"=>"01a1",
|
|
14
|
+
"data"=>{
|
|
15
|
+
"js_agent_api_key"=>"000-000-1"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
empty_policy = AddScriptTagPolicy.fromJson(policy_json_empty)
|
|
20
|
+
context "test empty agent" do
|
|
21
|
+
it "enabled is false" do
|
|
22
|
+
expect(empty_policy.policy_id).to eq("01a1")
|
|
23
|
+
expect(empty_policy.enabled).to eq(false)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
from_json = AddScriptTagPolicy.fromJson(policy_json_one)
|
|
28
|
+
context "tests xss is true and enabled true" do
|
|
29
|
+
it "returns true" do
|
|
30
|
+
expect(from_json.policy_id).to eq("01a1")
|
|
31
|
+
expect(from_json.enabled).to eq(true)
|
|
32
|
+
expect(from_json.js_agent_api_key).to eq("000-000-1")
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module TCellAgent
|
|
4
|
+
module Policies
|
|
5
|
+
describe AppSensorPolicy do
|
|
6
|
+
policy_json_empty = {
|
|
7
|
+
"policy_id"=>"01a1",
|
|
8
|
+
"data"=>{
|
|
9
|
+
"options"=>{}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
policy_json_one = {
|
|
14
|
+
"policy_id"=>"01a1",
|
|
15
|
+
"data"=>{
|
|
16
|
+
"options"=>{
|
|
17
|
+
"xss"=>true
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
empty_policy = AppSensorPolicy.fromJson(policy_json_empty)
|
|
23
|
+
context "test empty agent" do
|
|
24
|
+
it "enabled is false" do
|
|
25
|
+
expect(empty_policy.policy_id).to eq("01a1")
|
|
26
|
+
expect(empty_policy.enabled).to eq(false)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
from_json = AppSensorPolicy.fromJson(policy_json_one)
|
|
31
|
+
context "tests xss is true and enabled true" do
|
|
32
|
+
it "returns true" do
|
|
33
|
+
expect(from_json.policy_id).to eq("01a1")
|
|
34
|
+
expect(from_json.enabled).to eq(true)
|
|
35
|
+
expect(from_json.option_enabled?("xss")).to eq(true)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module TCellAgent
|
|
4
|
+
module Policies
|
|
5
|
+
describe ClickjackingPolicy do
|
|
6
|
+
content_security_policy_json = {
|
|
7
|
+
"policy_id"=>"00a1",
|
|
8
|
+
"headers"=>[
|
|
9
|
+
{"name"=>"csp", "value"=>"csp header value"}
|
|
10
|
+
]
|
|
11
|
+
}
|
|
12
|
+
csp_from_json = ClickjackingPolicy.fromJson(content_security_policy_json)
|
|
13
|
+
context "initialized with 3 items" do
|
|
14
|
+
it "returns true" do
|
|
15
|
+
expect(csp_from_json.policy_id).to eq("00a1")
|
|
16
|
+
expect(csp_from_json.headers[0].type).to eq("csp")
|
|
17
|
+
expect(csp_from_json.headers[0].value).to eq("csp header value")
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
context "headers match up appropriately" do
|
|
21
|
+
it "returns content-security-policy headers" do
|
|
22
|
+
expect(ClickjackingPolicy.cspHeadersForType("csp")).to match_array(["Content-Security-Policy"])#,"X-Content-Security-Policy","X-WebKit-CSP"])
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
describe ContentSecurityPolicy do
|
|
27
|
+
content_security_policy_json = {
|
|
28
|
+
"policy_id"=>"01a1",
|
|
29
|
+
"headers"=>[
|
|
30
|
+
{"name"=>"csp-header-is-bad", "value"=>"csp header value"}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
csp_policy = ClickjackingPolicy.fromJson(content_security_policy_json)
|
|
34
|
+
context "csp header example, invalid header" do
|
|
35
|
+
it "returns false" do
|
|
36
|
+
expect(csp_policy.headers.length).to eq(0)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
describe ClickjackingPolicy do
|
|
41
|
+
content_security_policy_json = {
|
|
42
|
+
"policy_id"=>"01a1",
|
|
43
|
+
"headers"=>[
|
|
44
|
+
{"name"=>"csp", "value"=>"value123\\nabc"}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
csp_policy = ClickjackingPolicy.fromJson(content_security_policy_json)
|
|
48
|
+
context "secure header, value is bad" do
|
|
49
|
+
it "returns false" do
|
|
50
|
+
expect(csp_policy.headers.length).to eq(0)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
describe ClickjackingPolicy do
|
|
55
|
+
content_security_policy_json = {
|
|
56
|
+
"policy_id"=>"01a1",
|
|
57
|
+
"headers"=>[
|
|
58
|
+
{"name"=>"csp", "value"=>"value normal", "report-uri"=>"https://example.com/abcdde"}
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
csp_policy = ClickjackingPolicy.fromJson(content_security_policy_json)
|
|
62
|
+
context "secure header, report-uri seperate" do
|
|
63
|
+
it "returns false" do
|
|
64
|
+
expect(csp_policy.headers.length).to eq(1)
|
|
65
|
+
expect(csp_policy.headers[0].value).to eq("value normal; report-uri https://example.com/abcdde")
|
|
66
|
+
expect(csp_policy.headers[0].value("1","2","3")).to eq("value normal; report-uri https://example.com/abcdde?tid=1&sid=2&uid=3")
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|