Skip to content
This repository was archived by the owner on Jan 15, 2019. It is now read-only.

Commit 29e603a

Browse files
committed
Minor documentation + logging improvements
1 parent a03b78b commit 29e603a

File tree

8 files changed

+148
-118
lines changed

8 files changed

+148
-118
lines changed

CssefClient/cssef-cli

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#!/usr/bin/python
2+
import logging
23
import sys
34
from getpass import getpass
45
from prettytable import PrettyTable
@@ -21,6 +22,7 @@ class Menu(object):
2122
endpoint['rpc_name'],
2223
endpoint['args'])
2324
self.menu_dict[endpoint['menu_path']] = command_inst
25+
logging.info("%d endpoints loaded" % len(self.menu_dict.keys()))
2426

2527

2628
def get_command(self, command_list):
@@ -40,7 +42,8 @@ class Menu(object):
4042
try:
4143
return self.menu_dict[menu_path]
4244
except KeyError:
43-
print menu_path
45+
#print menu_path
46+
logging.error(menu_path)
4447
raise NonExistantCommand
4548

4649
class ParseInput(object):
@@ -97,7 +100,8 @@ class ParseInput(object):
97100
value = self.remaining_args[index + 1]
98101
except IndexError:
99102
# There is no next error. Complain and quit
100-
sys.exit("Expected value in for argument, but got none.")
103+
logging.error("Expected value in for argument, but got none.")
104+
sys.exit(1)
101105
index += 1
102106
self.command_args[keyword] = value
103107
index += 1
@@ -115,12 +119,12 @@ def build_auth_dict(config):
115119
return tmp_dict
116120
# Add the username to the auth Dict
117121
if not config.username:
118-
print "No username was provided."
122+
logging.warning("No username was provided.")
119123
return None
120124
tmp_dict["username"] = config.username
121125
# Add the organization to the auth Dict
122126
if not config.organization:
123-
print "No organization was provided."
127+
logging.warning("No organization was provided.")
124128
return None
125129
tmp_dict["organization"] = config.organization
126130
# If a password is provided, we want to use that instead of the token
@@ -134,34 +138,30 @@ def build_auth_dict(config):
134138
tmp_dict["password"] = getpass()
135139
else:
136140
# Both values failed
137-
print "Neither password nor token were provided."
141+
logging.warning("Neither password nor token were provided.")
138142
return None
139143
return tmp_dict
140144

141145
def print_output(output):
142146
if output.value != 0:
143-
sys.stderr.write("The server is reporting the following error:\n")
144-
sys.stderr.write("\n".join(output.message)+"\n")
147+
logging.error("The server is reporting the following error:\n%s" % "\n".join(output.message))
145148
if output.table_headers:
146149
# Its a dictionary list, make a table and print it
147150
output_table = PrettyTable(output.table_headers)
148151
output_table.padding_width = 1
149152
for i in output.content:
150153
output_table.add_row(i.values())
151-
print output_table
154+
logging.info(output_table)
152155
else:
153156
# It's just a list of strings, print each one
154157
# TODO: Maybe I just shouldn't support this...
155158
for i in output.content:
156-
print i
157-
158-
if __name__ == "__main__":
159-
# # Ensure user data directory exists
160-
# if not os.path.exists(self.userDataDir):
161-
# os.makedirs(self.userDataDir)
159+
logging.info(i)
162160

161+
def main(cli_args):
162+
logging.basicConfig(format='[%(levelname)s] %(message)s')
163163
# Set up and configure the client
164-
user_input = ParseInput(sys.argv[1:])
164+
user_input = ParseInput(cli_args)
165165
client = cssefclient.CssefClient()
166166
client.config.load_config_file(client.config.global_config_path)
167167
client.config.load_config_file(client.config.config_path)
@@ -185,9 +185,12 @@ if __name__ == "__main__":
185185

186186
# Make sure our provided input matches what we were told to send to the client
187187
if not command.validate_input(user_input.command_args):
188-
print "Invalid arguments"
188+
logging.error("Invalid arguments")
189189
sys.exit()
190190

191191
output_obj = client.call_endpoint(command, user_input.command_args)
192192
print_output(output_obj)
193193
sys.exit(output_obj.value)
194+
195+
if __name__ == "__main__":
196+
main(sys.argv[1:])

CssefClient/cssefclient/__init__.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import sys
55
import time
66
import yaml
7+
import logging
78
from jsonrpcclient.http_server import HTTPServer
89
from cssefclient.tasks import RenewToken
910
from cssefclient.tasks import AvailableEndpoints
@@ -37,8 +38,6 @@ def load_token(self, auth):
3738
token = load_token_file(self.config.token_file)
3839
if token:
3940
self.config.token = token
40-
else:
41-
print "[ERROR] Failed to load token"
4241
# Renew the token if it's enabled
4342
if self.config.token_renewal_enabled:
4443
return RenewToken(self.config).execute(auth=auth)
@@ -117,7 +116,7 @@ def load_config_file(self, config_path):
117116
try:
118117
config_dict = yaml.load(open(config_path, 'r'))
119118
except IOError:
120-
print "[WARNING] Failed to load config file at '%s'." % config_path
119+
logging.warning("Failed to load config file at '%s'." % config_path)
121120
return None
122121
if config_dict:
123122
self.load_config_dict(config_dict)
@@ -142,7 +141,7 @@ class will be ignored (this will be logged).
142141
if "verbose" in config_dict:
143142
setattr(self, "verbose", bool(config_dict.pop("verbose")))
144143
if self.verbose:
145-
print "[LOGGING] Configuration 'verbose' set to 'True'."
144+
logging.info("Configuration 'verbose' set to 'True'.")
146145
for i in config_dict:
147146
if hasattr(self, i.replace('-', '_')):
148147
# Set the attribute
@@ -155,14 +154,14 @@ class will be ignored (this will be logged).
155154
value = value.lower() == 'true'
156155
setattr(self, setting, value)
157156
if self.verbose:
158-
print "[LOGGING] Configuration '%s' set to '%s'." % (i, value)
157+
logging.info("Configuration '%s' set to '%s'." % (i, value))
159158
elif isinstance(config_dict[i], dict):
160159
# This is a dictionary and may contain additional values
161160
self.load_config_dict(config_dict[i])
162161
else:
163162
# We don't care about it. Just skip it!
164163
# if self.verbose:
165-
print "[WARNING] Ignoring invalid setting '%s'." % i
164+
logging.warning("Ignoring invalid setting '%s'." % i)
166165

167166
class EndpointsLoader(object):
168167
def __init__(self, config):
@@ -181,8 +180,9 @@ def load(self):
181180
output = self.load_from_server()
182181
if not output:
183182
# Raise an error since we failed to load the endpoints
184-
print output.value
185-
print output.message
183+
logging.error("Value: %d, Message: %s" % (output.value, output.message))
184+
#print output.value
185+
#print output.message
186186
raise Exception
187187
self.endpoints = output.content
188188
self.update_cache()
@@ -206,7 +206,7 @@ def determine_source(self):
206206
cache_last_mod_time = os.stat(self.config.endpoint_cache_file).st_mtime
207207
except OSError:
208208
# Failed to read from the file, load from server
209-
print "Failed to read cache file: %s" % self.config.endpoint_cache_file
209+
logging.warning("Failed to read cache file: %s" % self.config.endpoint_cache_file)
210210
# TODO: Libraries shouldn't print! (I thought this was a library,
211211
# not a printing press! :P)
212212
self.from_cache = False

CssefClient/cssefclient/tasks.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import logging
12
from cssefclient.utils import RPCEndpoint
23
from cssefclient.utils import save_token_file
34

@@ -30,7 +31,6 @@ def __init__(self, config):
3031
self.rpc_name = 'renewtoken'
3132

3233
def execute(self, **kwargs):
33-
print kwargs
3434
# # Populate the arguments to pass to the login
3535
# # Here we only need the username and the token
3636
# if not kwargs.get('username'):
@@ -57,9 +57,9 @@ def execute(self, **kwargs):
5757
if not self.config.token_auth_enabled:
5858
# Bail if token authentication is disabled
5959
if self.config.verbose:
60-
print "[ERROR] Logging in requires that token authentication be \
60+
logging.error("[ERROR] Logging in requires that token authentication be \
6161
enabled. Set 'token_auth_enabled: True' in your \
62-
configuration."
62+
configuration.")
6363
return None
6464
# Attempt to log in
6565
return_dict = super(Login, self).execute(**kwargs.get('auth'))

CssefClient/cssefclient/utils.py

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import sys
44
import stat
55
import time
6+
import logging
67
from datetime import datetime
78

89
class CommandOutput(object):
@@ -75,11 +76,11 @@ def execute(self, **kwargs):
7576
created with values describing the encountered exception.
7677
"""
7778
if self.config.verbose:
78-
print "[LOGGING] Calling rpc with name '%s'." % self.rpc_name
79+
logging.info("Calling rpc with name '%s'." % self.rpc_name)
7980
# "Serialize" datetime objects
8081
for i in kwargs:
8182
if isinstance(kwargs[i], datetime):
82-
print "Found datetime object"
83+
logging.debug("Found datetime object")
8384
# Overwrite the datetime object to a unix timestamp representing the same time
8485
kwargs[i] = time.mktime(kwargs[i].timetuple())
8586
# Try the api call
@@ -105,17 +106,15 @@ def load_token_file(token_file):
105106
"""
106107
# Make sure the file exists
107108
if not os.path.isfile(token_file):
108-
sys.stderr.write("[WARNING] Token file not found. Cannot use token authentication.\n")
109-
sys.stderr.flush()
109+
logging.warning("Token file not found. Cannot use token authentication.")
110110
return False
111111
# Now make sure that only we have access to it
112112
file_permissions = os.stat(token_file).st_mode
113113
permissions_denied = [stat.S_IRGRP, stat.S_IWGRP, stat.S_IXGRP,
114114
stat.S_IROTH, stat.S_IWOTH, stat.S_IXOTH]
115115
for i in permissions_denied:
116116
if bool(file_permissions & i):
117-
sys.stderr.write("Token file may not have any permissions for group or other.\n")
118-
sys.stderr.flush()
117+
logging.warning("Token file may not have any permissions for group or other.")
119118
return False
120119
# Now actually read in the file
121120
token = open(token_file, 'r').read()

CssefServer/cssefserver/tasks.py

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,25 @@
88
from cssefserver.taskutils import client_failed_login_output
99

1010
class AvailableEndpoints(CssefRPCEndpoint):
11+
"""RPC task to get all available RPC endpoints.
12+
13+
Attributes:
14+
name (str): Human readable name of the endpoint. "Available Endpoints"
15+
rpc_name (str): Name of the endpoint as registered with the HTTP api. "availableendpoints"
16+
menu_path (none): Blank because this is not something a user will manually call
17+
require_auth (bool): Authentication is not required to call this endpoint
18+
"""
19+
1120
name = "Available Endpoints"
1221
rpc_name = "availableendpoints"
1322
menu_path = None
1423
require_auth = False
1524
def on_request(self):
16-
"""Celery task to get all available celery endpoints.
25+
"""Returns a response containing the RPC endpoints
1726
1827
Returns:
19-
A return_dict dictionary containing the results of the API call. The
20-
content is a list of dictionaries containing information about the
21-
available endpoints.
28+
(dict): A return_dict where 'content' is a list of dictionaries containing
29+
the available endpoints and relevant information about those endpoints.
2230
"""
2331

2432
# Stuff in here is not being copied properly, which is resulting in

docs/source/about.rst

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
About
2+
=====
3+
4+
.. attention::
5+
The project is still undergoing heavy development. The state of the project
6+
may change at any time - please be aware that some information here may be
7+
out of date.
8+
9+
The Cyber Security Scoring Engine Framework (CSSEF) is meant to be an easy to
10+
use framework for hosting various types of security competitions. By making
11+
competition scoring and management easier, the hope is that more time and
12+
energy may be spent setting up the competition environment itself. Many of the
13+
features and requirements were determined by the competitions hosted inhouse
14+
by the University of Alaska's Cyber Security Club, which attended the National
15+
Cyber Collegdet Defense Competition several years in a row. While initial
16+
development focused on providing utilities for CCDC-like competitions, the
17+
project evolved to facilitate other types of competitions, so it may be of use
18+
to other organizations, regardless of type of competition being conducted.
19+
20+
Features
21+
--------
22+
Features include but are certainly not limited to the following. Please see
23+
the respective section of documentation for more inforation on any particular
24+
feature.
25+
26+
- Multiple organizations
27+
- Easy to use command line interface
28+
- Modern(ish) web client
29+
- Plugin interface for multiple types of competitions
30+
- A prebuilt plugin for CCDC-like competitions (see the plugins section)
31+
32+
How It Works
33+
------------
34+
35+
.. attention::
36+
At this time, the CTF plugin does not exist, so these particular endpoinds
37+
do not exist. This scenario also assumes the server has been configured
38+
and the users have all made appropriet changes to their local configurations.
39+
40+
Lets say you want to host a capture the flag competition on your campus. You
41+
would install the plugin package for the CTF competition on the host running
42+
the CSSEF server. Then enable the plugin for the server, and configure a new
43+
competition for your organization.
44+
45+
::
46+
pip install -y cssef-ctf
47+
echo "- cssefctf.CaptureTheFlag" >> /etc/cssef/cssefd.yml
48+
cssefd restart
49+
cssef-cli ctf add --name "My CTF"
50+
cssef-cli ctf flag add --ctf "My CTF" --name "First Flag" --hint "This is a hint" --value "abc123"
51+
52+
Assuming that was all you wanted in your competition, begin the competition,
53+
thus allowing the competitiors to submit guesses.
54+
55+
::
56+
cssef-cli ctf start --ctf "My CTF"
57+
58+
::
59+
cssef-cli ctf guess --ctf "My CTF" --flag "First Flag" --value "guess?"
60+
cssef-cli ctf guess --ctf "My CTF" --flag "First Flag" --value "another try"
61+
62+
If the competition plugin you are using supports web interface displays,
63+
you can manage the competition through a CSSEF web server. The web server runs
64+
as a separate service, and requires additional setup not covered here.
65+
66+
Framework Components
67+
--------------------
68+
69+
Server
70+
~~~~~~
71+
The server allows for management of "plugins", which provide resources for
72+
running competitions. These plugins consume the various endpoints and features
73+
provided by the framework in such a way that no two competitions collide with
74+
each other. This means you can host several capture the flag and a CCDC-like
75+
competitions on the same service. The server communicates with clients via HTTP
76+
RPC calls, and uses sqlalchemy for databasing. For additional information, see
77+
the `server documentation`_.
78+
79+
.. _server documentation: server.rst
80+
81+
Client
82+
~~~~~~
83+
The client package provides endpoints for client applications, as well as a
84+
basic command line tool. If you plan to install the web client, this package
85+
is a required depenancy. See the `client documentation`_ for more information,
86+
or the `command line`_ documentation for cli reference.
87+
88+
.. _client documentation: client.rst
89+
.. _command line: cli.rst
90+
91+
Web Client
92+
~~~~~~~~~~
93+
The web client is meant to be an easy and painless tool for interacting with
94+
the server, as well as the various features provided by competition plugins-
95+
especially when competitors may be submitting data during competition
96+
environments that don't actually have the cssef client available. The web
97+
client is currently using django, which itself simply consumes endpoints
98+
within the cssef client. For more information about the web client, see the
99+
cssef webui documentation.

docs/source/index.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Welcome to Cssef's documentation!
1010
:maxdepth: 2
1111
:caption: Overview
1212

13-
introduction
13+
about
1414
getting-started
1515

1616
.. toctree::

0 commit comments

Comments
 (0)