Skip to content

Security

Keith Sterling edited this page Jul 31, 2017 · 12 revisions

Security

Program-Y provides 2 key elements of security

Authentication

    def ask_question(self, bot, clientid, sentence) -> str:

        if self.authentication is not None:
            if self.authentication.authenticate(clientid) is False:
                logging.error("[%s] failed authentication!")
                return self.authentication.configuration.denied_srai

The base class is defined as

class Authenticator(object):

    def __init__(self, configuration: BrainSecurityConfiguration):
        self._configuration = configuration

    @property
    def configuration(self):
        return self._configuration

    def get_default_denied_srai(self):
        return self.configuration.denied_srai

    def authenticate(self, clientid: str):
        return False

A very simple implementation of this class is a class that only authenticates those client ids that are contained within the 'authorised' array.

More advanced classes would call an external service to check the client id was truly authenticated.

class ClientIdAuthenticationService(Authenticator):

    def __init__(self, configuration: BrainSecurityConfiguration):
        Authenticator.__init__(self, configuration)
        self.authorised = [
            "console"
        ]

    # Its at this point that we would call a user auth service, and if that passes
    # return true, appending the user to the known authorised list of user
    # This is a very naive approach, and does not cater for users that log out, invalidate
    # their credentials, or have a TTL on their credentials
    # #Exercise for the reader......
    def _auth_clientid(self, clientid):
        authorised = False # call user_auth_service()
        if authorised is True:
            self.authorised.append(clientid)
        return authorised

    def authenticate(self, clientid: str):
        try:
            if clientid in self.authorised:
                return True
            else:
                if self._auth_clientid(clientid) is True:
                    return True

                return False
        except Exception as excep:
            logging.error(str(excep))
            return False

Configuration is defined as

    security:
        authentication:
            classname: programy.utils.security.authenticate.clientidauth.ClientIdAuthenticationService
            denied_srai: AUTHENTICATION_FAILED

Authorisation

  • User. A user is a single entity. A user can both be assigned specific roles and inherity roles through inclusion in one or more groups
  • Group. A collection of users that has one of more associated roles.
  • Role. A string definition of an activity that a user of group can perform.
	<category>
		<pattern>ALLOW ACCESS</pattern>
		<template>
		    <authorise role="root">
				Access Allowed
			</authorise>
		</template>
	</category>

The base class for all authorisation is defined as

class Authoriser(object):

    def __init__(self, configuration: BrainSecurityConfiguration):
        self._configuration = configuration

    @property
    def configuration(self):
        return self._configuration

    def get_default_denied_srai(self):
        return self.configuration.denied_srai

    def authorise(self, userid, role):
        return False

A basic implementation of this base class which performs User, Group and ROle based authorisation is as follows

class BasicUserGroupAuthorisationService(Authoriser):

    def __init__(self, config: BrainSecurityConfiguration):
        Authoriser.__init__(self, config)
        self.load_users_and_groups()

    def load_users_and_groups(self):

        self._users = {}
        self._groups = {}

        if self.configuration.usergroups is not None:
            loader = UserGroupLoader()
            self._users, self._groups = loader.load_users_and_groups_from_file(self.configuration.usergroups)
        else:
            logging.warning("No user groups defined, authorisation tag will not work!")

    def authorise(self, clientid, role):
        if clientid not in self._users:
            raise AuthorisationException("User [%s] unknown to system!"%clientid)

        if clientid in self._users:
            user = self._users[clientid]
            return user.has_role(role)
        else:
            return False

Configuration is defined as

    security:
        authorisation:
            classname: programy.utils.security.authorise.usergroupsauthorisor.BasicUserGroupAuthorisationService
            denied_srai: AUTHORISATION_FAILED
            usergroups: $BOT_ROOT/config/roles.yaml

Format of the roles file is as follows

users:
  console:
    roles:
      user
    groups:
      sysadmin

groups:
  sysadmin:
    roles:
      root, admin, system
    groups:
      user

  user:
    roles:
      ask
Clone this wiki locally