-
Notifications
You must be signed in to change notification settings - Fork 135
Security Role Based
Program-Y provides 2 key elements of security
Authentication takes place directly within brain within the core code. Each time a user asks a question, the method ask_question() is called. One of its parameters is 'clientid' which is the id associated with the user asking the question. For clients like console this is always 'console' but for more online clients such as webchat, xmpp or twitter, its up to the developer to decide which id to use and how to make sure clientid is set appropriately ( more on this to follow )
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 authentication service is defined in a dynamically loaded class, the base class of which is defined as follows
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
The configuration to enable this capability is held within brain seection of config.yaml, within the security sub section as follows
brain:
security:
authentication:
classname: programy.utils.security.authenticate.clientidauth.ClientIdAuthenticationService
denied_srai: AUTHENTICATION_FAILED
- classname. Defines the full python path of the class to loaded which implements the base class 'Authenticator'
- denied_srai. If authentication fails, then the interpreter excutes the grammar defined in this setting as an SRAI operation. Your aiml files should contain this as a category pattern with appropraite text showing access denied.
Authorisation is currently implemented via basic User, Group and Role model, defined as
- User. A user is a single entity. A user can both be assigned specific roles and inherited 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.
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
To wrap an AIML grammar in authorisation, wrap the template in an 'authorise' tag, an example of which is shown below. Here if 'ALLOW ACCESS' is asked and the user does not have the 'root' role associated with them then grammar defined in denied_srai.
<category>
<pattern>ALLOW ACCESS</pattern>
<template>
<authorise role="root">
Access Allowed
</authorise>
</template>
</category>
Email: keiffster@gmail.com | Twitter: @keiffster | Facebook: keith.sterling | LinkedIn: keithsterling | My Blog
- Home
- Background
- Guiding Principles
- Reporting an Issue
- Installation
- You And Your Bot
- Bots
- Clients
- Configuration
- AIML
- Sentence Splitting
- Natural Langauge Processing
- Normalization
- Spelling
- Sentiment Analysis
- Translation
- Security
- Hot Reload
- Logging
- Out of Band
- Multi Language
- RDF Support
- Rich Media
- Asynchronous Events
- Triggers
- External Services
- Dynamic Sets, Maps & Vars
- Extensions
- Pre & Post Processors
- Custom Nodes
- The Brain Tree
- Utilities
- Building It Yourself
- Creating Your Own Bot
- Contributing
- Performance Testing
- FAQ
- History
- Website