cssefserver package

Submodules

cssefserver.api module

class cssefserver.api.User(server, model)

Bases: cssefserver.ModelWrapper

Defines a basic User object.

This subclasses ModelWrapper, and uses user.models.User as it’s database model.

model_object

UserModel – Defines the model the object is associated with

fields

list – Lists the fields within the associated model to present to the client

model_object

alias of User

fields = ['name', 'username', 'password', 'description', 'organization']
password

Password for the user.

This wraps the password attribute of the associated model.

Returns:Contains the hash of the users password. The hash itself can be extracted by reading the PasswordHash.hash attribute. See PasswordHash for more information.
Return type:PasswordHash

Example

The following is an example shows instantiating an existing user via its pkid, displaying the value type of its password attribute, then retrieving the password hash from the PasswordHash object.:

>>> u = User(pkid = 1)
>>> type(u.password)
<type 'PasswordHash'>
>>> print u.password.hash
abiglonghashisprintedhere
>>>
classmethod from_dict(server, kw_dict)
authorized(auth_dict, group)
authenticate(auth_dict)

Attempt to authenticate with whatever information was provided

The authdict may contain a token or key. Check if either is present and attempt to authenticate with that. It will attempt to authenticate with the token first. If that fails and autentication failover is not enabled, the function will just return. If authentication failover is enabled and the password is provided, it will try to authenticate with that. If no valid form of authentication is provided, authentication will fail.

Parameters:auth_dict (dict) – A dictionary with a password or token in it.
Returns:True if the passwords match, false if not.
Return type:bool
authenticate_token(raw_token)

Check if the provided token is valid for this user.

This abstracts the process setting the new value in the database. This will eventually require additional processes to authorize the moving of an account from one organization to another.

Parameters:value (int) – The organization ID of the organization to put the user in.
Returns:True if the token belongs to the user and contains the correct user ID and organization ID. False if the token does not belong to the user, or contains an incorrect user ID or organization ID.
Return type:bool

Example

<todo>

authenticate_password(password)

Check if the provided plaintext password is valid for this user.

This will check that the provided password matches the users password. The actual password comparison is done through the __eq__ attribute of the PasswordHash class. A token is created and returned if the password is correct, allowing the user to make further requests without having to reauthenticate each time.

Parameters:password (str) – Plaintext password candidate
Returns:True if the passwords match, false if not.
Return type:bool
get_new_token()
class cssefserver.api.Organization(server, model)

Bases: cssefserver.ModelWrapper

model_object

alias of Organization

fields = ['name', 'url', 'description', 'max_members', 'max_competitions', 'can_add_users', 'can_delete_users', 'can_add_competitions', 'can_delete_competitions']
as_dict()

Provides a dictionary representation of the Organization

Builds and returns a dictionary representing the values in the Organizations fields attribute. Organization.as_dict() includes the readonly attribute deletable.

Returns:A dictionary that represents the same values in the object.
Return type:dict
is_deletable()

Checks if the organization can be deleted.

Returns:True if the organization can be deleted, false if it cannot be deleted.
Return type:bool
get_num_members()

Gets the current number of competitions belonging to the organization

This gets the “cached” count of the current number of competitions that belong to the organization.

Returns:The number of competitions that are part of the organization
Return type:int
set_num_members()

Gets the current number of members in the organization

This gets the “cached” count of the current number of users that are part of the organization.

Returns:The number of users that are part of the oragnizaiton
Return type:int
get_num_competitions()
get_members(**kwargs)
get_member(**kwargs)

Gets a specific member that belongs to the organization

This will retrieve a specific user that belongs to the organization.

Parameters:**kwargs – Keyword arguments that define the user to match.
Returns:A user that belongs to the organization
Return type:User
cssefserver.api.authorize_access(server, auth_dict, config)

cssefserver.databaseutils module

class cssefserver.databaseutils.BaseModel

Bases: object

A base model for the sqlalchemy models

I defined a special base model in an attempt to set a prefix on the database tables. That functionality was broken at one point and hasn’t been restored.

pkid = Column(None, Integer(), table=None, primary_key=True, nullable=False)
cssefserver.databaseutils.get_foreign_key(cls, column='pkid')

Gets foreign key of another model

Parameters:
  • cls (Model) – Model we want to get the foreign key for
  • column (string) – The specific column to get a key for. Default is pkid. I’m not sure if you would even want to change the column.
Returns:

Instantiated with the tablename and column name of the provided model.

Return type:

ForeignKey

cssefserver.databaseutils.create_database_connection(database_path='')

Returns a database session for the specified database

cssefserver.errors module

This list of CSSEF errors will be expanded and modified as more errors are added.

Authentication Errors:

Allotted error codes: 30 - 49

  • 30 - IncorrectCredentials
  • 31 - TokenDisallowed
  • 32 - TokenExpired
  • 33 - BadAuthSource

General User Errors:

Allotted error codes: 50 - 150

  • 50 - InvalidPkidValue
exception cssefserver.errors.CssefException

Bases: exceptions.Exception

A basic CSSEF exception to be subclassed

This class is meant to be subclassed by actual errors, setting the value for ‘value’ and ‘message’. Any CssefExcption can be easily prepared for the user by calling as_return_dict().

value = None
message = None
log()
as_dict()

Return the error as a return dictionary

This returns a “return_dict”, which is just a dictionary containing the keys ‘value’, ‘message’, and ‘content’. This will just create the return dict based on the properties value and message. There is no content. The error is also logged via journal.send().

Returns:A dictionary with the keys ‘value’ and ‘message’ with values of the corresponding properties. An example dict:

{'value': 1, 'message': ['Example message'], 'content': []}

Return type:dict
exception cssefserver.errors.CssefPluginMalformedName(plugin_value)

Bases: cssefserver.errors.CssefException

value = 9000
message = ['Incorrectly formatted plugin entry.']
exception cssefserver.errors.CssefPluginInstantiationError(plugin_value)

Bases: cssefserver.errors.CssefException

value = 9001
message = ['Module failed to instantiate.']
exception cssefserver.errors.CssefObjectDoesNotExist(message)

Bases: exceptions.Exception

Expection for model instantiation errors

This is the base exception that is subclassed as ObjectDoesNotExist in the ModelWrapper class. It is thrown when one tries to instantiate the model with data identifying a particular database record that does not exist. I may eventually change this to subclass CssefException rather than Exception, but there may be some unintended consequences to that.

exception cssefserver.errors.IncorrectCredentials

Bases: cssefserver.errors.CssefException

Generic authentication failure exection

This is used in cases where enough authentication information was provided but some part of it was incorrect.

value = 30
message = ['Bad username or password']
exception cssefserver.errors.TokenDisallowed

Bases: cssefserver.errors.CssefException

Error returned when token authentication is disabled

If the server has token authentication disabled, then this error will be returned to the user indicating that they must provide a password rather than using a token.

value = 31
message = ['Token may not be used during login.']
exception cssefserver.errors.NoUsernameProvided

Bases: cssefserver.errors.CssefException

Username field was missing

Used when the username is missing from the provided authentication information.

value = 32
message = ['No username provided.']
exception cssefserver.errors.NoOrganizationProvided

Bases: cssefserver.errors.CssefException

Organization field was missing

Used when the organization is missing from the provided authentication information.

value = 33
message = ['No organization provided.']
exception cssefserver.errors.NonexistentUser

Bases: cssefserver.errors.CssefException

Error returned when the username does not exist

This error is returned when a specified user does not exist. This should not be used within the authentication process, as it gives information about what users do and don’t exist.

value = 34
message = ['Unable to find user with provided username.']
exception cssefserver.errors.PermissionDenied

Bases: cssefserver.errors.CssefException

value = 35
message = ['Permission id denied.']
exception cssefserver.errors.AuthFindsMultipleUsers

Bases: cssefserver.errors.CssefException

Error returned when multiple users have the same name

This error is thrown when there are multiple users with the same username within the same organization. This is extremely bad, and will idealy never be seen.

value = 36
message = ['Username + Organization returned multiple users.']
exception cssefserver.errors.AuthIncorrectAdminToken

Bases: cssefserver.errors.CssefException

Error return when an invalid token was provided

This error is thrown when the authentication token is invalid in some way.

value = 37
message = ['Provided auth-token was incorrect.']
exception cssefserver.errors.InvalidPkidValue

Bases: cssefserver.errors.CssefException

Indicates the provided PKID value was bad

This error indicates that there was a problem interpreting the value provided for the pkid of some object.

value = 50
message = ['Provided pkid was not valid.']
exception cssefserver.errors.MaxCompetitionsReached(max_competitions)

Bases: exceptions.Exception

exception cssefserver.errors.MaxMembersReached(max_members)

Bases: exceptions.Exception

cssefserver.models module

class cssefserver.models.Organization(**kwargs)

Bases: sqlalchemy.ext.declarative.api.Base

This is a base User SQLAlchemy model.

deletable
can_add_users
can_delete_users
can_add_competitions
can_delete_competitions
name
url
description
max_members
max_competitions
num_members
num_competitions
pkid
class cssefserver.models.User(**kwargs)

Bases: sqlalchemy.ext.declarative.api.Base

This is a base User SQLAlchemy model.

organization
last_login
name
username
password
description
pkid

cssefserver.tasks module

class cssefserver.tasks.OrganizationAdd(server)

Bases: cssefserver.taskutils.CssefRPCEndpoint

name = 'Organization Add'
rpc_name = 'organizationadd'
menu_path = 'organization.add'
on_request_args = ['auth']
on_request(auth, **kwargs)

RPC task to create a new organization.

Parameters:**kwargs – Keyword arguments to be passed onto Organziation.from_dict()
Returns:A return_dict dictionary containing the results of the API call. See get_empty_return_dict for more information.
class cssefserver.tasks.OrganizationDel(server)

Bases: cssefserver.taskutils.CssefRPCEndpoint

name = 'Organization Delete'
rpc_name = 'organizationdel'
menu_path = 'organization.del'
takes_kwargs = False
on_request_args = ['auth', 'pkid']
on_request(auth, pkid)

RPC task to delete an existing organization.

Parameters:pkid (int) – The ID of the organization to delete
Returns:A return_dict dictionary containing the results of the API call. See get_empty_return_dict for more information.
class cssefserver.tasks.OrganizationSet(server)

Bases: cssefserver.taskutils.CssefRPCEndpoint

name = 'Organization Set'
rpc_name = 'organizationset'
menu_path = 'organization.set'
on_request_args = ['auth', 'pkid']
on_request(auth, pkid, **kwargs)

RPC task to edit an existing organization.

Parameters:
  • pkid (int) – The ID of the organization to edit
  • **kwargs – Keyword arguments for values to change in the organization
Returns:

A return_dict dictionary containing the results of the API call. See get_empty_return_dict for more information.

class cssefserver.tasks.OrganizationGet(server)

Bases: cssefserver.taskutils.CssefRPCEndpoint

name = 'Organization Get'
rpc_name = 'organizationget'
menu_path = 'organization.get'
on_request_args = ['auth']
on_request(auth, **kwargs)

RPC task to get one or more existing organization.

Parameters:**kwargs – Keyword arguments to filter organization by
Returns:A return_dict dictionary containing the results of the API call. See get_empty_return_dict for more information.
class cssefserver.tasks.UserAdd(server)

Bases: cssefserver.taskutils.CssefRPCEndpoint

name = 'User Add'
rpc_name = 'useradd'
menu_path = 'user.add'
on_request_args = ['auth']
on_request(auth, **kwargs)

RPC task to create a new user.

Parameters:
  • organization (int) – The ID of the organization the user belongs to
  • **kwargs – Keyword arguments to be passed onto User.from_dict()
Returns:

A return_dict dictionary containing the results of the API call. See get_empty_return_dict for more information.

class cssefserver.tasks.UserDel(server)

Bases: cssefserver.taskutils.CssefRPCEndpoint

name = 'User Delete'
rpc_name = 'userdel'
menu_path = 'user.del'
takes_kwargs = False
on_request_args = ['auth', 'pkid']
on_request(auth, pkid)

RPC task to delete an existing user.

Parameters:pkid (int) – The ID of the user to delete
Returns:A return_dict dictionary containing the results of the API call. See get_empty_return_dict for more information.
class cssefserver.tasks.UserSet(server)

Bases: cssefserver.taskutils.CssefRPCEndpoint

name = 'User Set'
rpc_name = 'userset'
menu_path = 'user.set'
on_request_args = ['auth', 'pkid']
on_request(auth, pkid, **kwargs)

RPC task to edit an existing user.

Parameters:
  • pkid (int) – The ID of the user to edit
  • **kwargs – Keyword arguments for values to change in the user
Returns:

A return_dict dictionary containing the results of the API call. See get_empty_return_dict for more information.

class cssefserver.tasks.UserGet(server)

Bases: cssefserver.taskutils.CssefRPCEndpoint

name = 'User Get'
rpc_name = 'userget'
menu_path = 'user.get'
on_request_args = ['auth']
on_request(auth, **kwargs)

RPC task to get one or more existing users.

Parameters:**kwargs – Keyword arguments to filter users by
Returns:A return_dict dictionary containing the results of the API call. See get_empty_return_dict for more information.
class cssefserver.tasks.RenewToken(server)

Bases: cssefserver.taskutils.CssefRPCEndpoint

name = 'Renew Token'
rpc_name = 'renewtoken'
menu_path = 'user.renewtoken'
takes_kwargs = False
on_request_args = ['auth']
on_request(auth)

RPC task to get a more up to date authentication token.

Parameters:
  • username – The username of the account the token belongs to
  • organization – The organization id of the account the token belongs to
  • token – The current token proving authentication
Returns:

A return_dict dictionary containing the results of the API call. The content field contains the new token if authentication was successful

class cssefserver.tasks.Login(server)

Bases: cssefserver.taskutils.CssefRPCEndpoint

name = 'Login'
rpc_name = 'login'
menu_path = 'user.login'
takes_kwargs = False
on_request_args = ['auth']
on_request(auth)

RPC task to login.

Returns:A return_dict dictionary containing the results of the API call. The content keyword will be a list containing the key for the session if the credentials were correct. Content will be empty if the credentials were incorrect, and value will be non-zero.
class cssefserver.tasks.AvailableEndpoints(server)

Bases: cssefserver.taskutils.CssefRPCEndpoint

Provides a list of endpoint sources

This will provide the list of raw enpoint source data, that being a list of dictionaries, where each dictionary is a single endpoint source containing information about the endpoints it provides.

name = 'Available Endpoints'
rpc_name = 'availableendpoints'
menu_path = None
on_request(*args)

RPC task to get all available celery endpoints.

Returns:A return message where the content is a list of dictionaries containing information about the available endpoints.
Return type:ReturnMessage
class cssefserver.tasks.AvailablePlugins(server)

Bases: cssefserver.taskutils.CssefRPCEndpoint

Provides a list of registered plugins

This returns a list of the plugins that the server is using.

name = 'Available Plugins'
rpc_name = 'availableplugins'
menu_path = 'availableplugins'
on_request(auth)

Get the list of plugins when the endpoint is requested

Returns:A list of the plugins, where each entry is a result of calling plugin_instance.as_dict().
Return type:ReturnMessage
cssefserver.tasks.endpoint_source()

Builds a dictionary defining the endpoints

This builds an “endpoint dictionary” that defines information about the endpoints in this module and where their source, relative to the overall project.

Returns:Dictionary with the keys ‘name’ and ‘endpoints’.
Return type:dict

cssefserver.taskutils module

class cssefserver.taskutils.CssefRPCEndpoint(server)

Bases: object

Base class for RPC endpoints

This class provides the functionality and utilities to create new RPC endpoints, consumable by clients.

name = None
rpc_name = None
menu_path = None
takes_kwargs = True
on_request_args = []
classmethod info_dict()
on_request(*args, **kwargs)

Abstract method for endpoint work

This method is where work specifically for fufilling requests goes. When the RPC class is called, on_request() is called and wrapped in error handling and message passing so the subclass doesn’t need to deal with it.

This method must return a dictionary. For best results (for the client), that dictionary should conform to the “return_dict” structure losely defined in the code base. That structure being {'value': int, 'message': [string], content: [string]}

cssefserver.taskutils.model_del(cls, server, pkid)

Genaric function to delete models

Parameters:
  • cls (Model) – The class type the pkid is refering to.
  • server (sqlalchemy.orm.Session) – The existing database connection to use.
  • pkid (int) – The ID of the model instance to be deleted.
Returns:

A return dict indicating the result of the operation.

Return type:

dict

cssefserver.taskutils.model_set(cls, server, pkid, **kwargs)

Genaric function to modify model values

Parameters:
  • cls (Model) – The class type the pkid is refering to.
  • server (sqlalchemy.orm.Session) – The existing database connection to use.
  • pkid (int) – The ID of the model instance to be modified.
Returns:

A return dict indicating the result of the operation.

Return type:

dict

cssefserver.taskutils.model_get(cls, server, **kwargs)

Genaric function to get models

Parameters:
  • cls (Model) – The class type to get entries from.
  • server (sqlalchemy.orm.Session) – The existing database connection to use.
Returns:

A return dict indicating the result of the operation.

Return type:

dict

cssefserver.utils module

class cssefserver.utils.PasswordHash(hash_)

Bases: object

This code pulled from http://variable-scope.com/posts/storing-and-verifying-passwords-with-sqlalchemy There are a couple minor changes to it, but most credit goes Elmer de Looff - Thank you!

classmethod new(password, rounds)

Creates a PasswordHash from the given password.

class cssefserver.utils.EndpointOutput(value=0, message='', content=None)

Bases: object

classmethod from_traceback()
log()
as_dict()

Module contents

class cssefserver.CssefServer(config=None)

Bases: object

The CSSEF Server object

The server coordinates the tracking of configurations, plugins, endpoints, database connection and socket connection (via jsonrpcserver) for incoming requests.

load_endpoint_sources()
load_endpoints()

Instantiates RPC endpoints

The RPC endpoing objects are all instantiated once, and then simply called any time a request is received for that endpoint. After the endpoint has been instantiated, it is added to the self.rpc_methods object, which is provided to the jsonrpcserver to define request routing.

Returns:None
start()

Starts running the service

This will start the process of importing plugins, creating the database connection, loading the rpc endpoints, and then registering and starting the builtin httpserver that is wrapped by the jsonrpcserver.

TODO: I may eventually change this so that this only starts the rpcserver, meaning the rest of the work can be done elsewhere, which would allow for better flexabiltiy and error handling.

Returns:None
class cssefserver.Configuration

Bases: object

Contains and loads server configuration values

There is one attribute for each configuration that can be set. Configurations can be loaded from a file or dictionary. When loading configurations, any hyphens wihtin key values will be converted to underscores so that the attribute can be set.

set_setting(setting_name, setting_value)
from_file(settings_file_path)

Load configuration from a file

This will read a yaml configuration file. The yaml file is converted to a dictionary object, which is just passed to load_settings_dict.

Parameters:settings_file_path (str) – A filepath to the yaml config file
Returns:None
from_dict(settings_dict)

Load configurations from a dictionary

This will convert strings with hyphens (-) to underscores (_) that way attributes can be added. Underscores are not used in the config files because I think they look ugly. That’s my only reasoning - deal with it. Any key within the dictionary that is not an attribute of the class will be ignored (this will be logged).

Parameters:settings_dict (dict) – A dictionary containing configurations and values
Returns:None
class cssefserver.PluginManager(module_list=None)

Bases: object

import_from_string(module_string)
import_from_list(module_list)
class cssefserver.Plugin

Bases: object

A base competition plugin class

This class provides the basic functionality for registering new competition plugins. More methods will be made available in the future to improve utility provided to subclasses.

name = ''
short_name = ''
endpoints = []
classmethod endpoint_info()
as_dict()
class cssefserver.ModelWrapper(server, model)

Bases: object

The base class for wrapping SQLAlchemy model objects

This class provides utilities for interacting with SQLAlchemy models in a clean manner. This should be subclassed by any other objects that will need to wrap a SQLAlchemy model object.

exception ObjectDoesNotExist(message)

Bases: cssefserver.errors.CssefObjectDoesNotExist

model_object = None
fields = []
define_properties()
dec_get(attribute)
dec_set(attribute)
get_id()
edit(**kwargs)
delete()
as_dict()
classmethod count(server, **kwargs)
classmethod search(server, **kwargs)
classmethod from_database(server, pkid)
classmethod from_dict(server, kw_dict)
class cssefserver.ParseInput(input_list)

Bases: object

parse_input()
parse_options()
parse_command()
parse_command_args()
cssefserver.main(raw_input_list)