Skip to content

Commit

Permalink
Fix #617. Fix #619
Browse files Browse the repository at this point in the history
  • Loading branch information
failys committed Apr 20, 2021
1 parent ad477dd commit 72aea65
Show file tree
Hide file tree
Showing 20 changed files with 4,681 additions and 42 deletions.
8 changes: 7 additions & 1 deletion cairis/config/cairis_model.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@
<!ELEMENT goal (tag*,goal_environment+)>
<!ATTLIST goal name CDATA #REQUIRED>
<!ATTLIST goal originator CDATA #REQUIRED>
<!ELEMENT goal_environment (definition,fit_criterion,issue,concern*,concern_association*)>
<!ELEMENT goal_environment (definition,fit_criterion,issue,concern*,concern_association*,policy?)>
<!ATTLIST goal_environment name CDATA #REQUIRED>
<!ATTLIST goal_environment category (Achieve | Maintain | Avoid | Improve | Increase | Maximise | Minimise | Accept | Transfer | Mitigate | Deter | Prevent | Detect | React) #REQUIRED>
<!ATTLIST goal_environment priority (Low | Medium | High) #REQUIRED>
Expand All @@ -294,6 +294,12 @@
<!ATTLIST concern_association target_nry (1 | a | 1..a) #REQUIRED>
<!ATTLIST concern_association target_name CDATA #REQUIRED>

<!ELEMENT policy EMPTY>
<!ELEMENT policy subject CDATA #REQUIRED>
<!ELEMENT policy access (read | write | interact) #REQUIRED>
<!ELEMENT policy resource CDATA #REQUIRED>
<!ELEMENT policy permission (allow | deny) #REQUIRED>

<!ELEMENT obstacle (tag*,obstacle_environment+)>
<!ATTLIST obstacle name CDATA #REQUIRED>
<!ATTLIST obstacle originator CDATA #REQUIRED>
Expand Down
8 changes: 7 additions & 1 deletion cairis/config/goals.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
<!ELEMENT goal (tag*,goal_environment+)>
<!ATTLIST goal name CDATA #REQUIRED>
<!ATTLIST goal originator CDATA #REQUIRED>
<!ELEMENT goal_environment (definition,fit_criterion,issue,concern*,concern_association*)>
<!ELEMENT goal_environment (definition,fit_criterion,issue,concern*,concern_association*,policy?)>
<!ATTLIST goal_environment name CDATA #REQUIRED>
<!ATTLIST goal_environment category (Achieve | Maintain | Avoid | Improve | Increase | Maximise | Minimise | Accept | Transfer | Mitigate | Deter | Prevent | Detect | React) #REQUIRED>
<!ATTLIST goal_environment priority (Low | Medium | High) #REQUIRED>
Expand All @@ -49,6 +49,12 @@
<!ATTLIST concern_association target_nry (1 | a | 1..a) #REQUIRED>
<!ATTLIST concern_association target_name CDATA #REQUIRED>

<!ELEMENT policy EMPTY>
<!ELEMENT policy subject CDATA #REQUIRED>
<!ELEMENT policy access (read | write | interact) #REQUIRED>
<!ELEMENT policy resource CDATA #REQUIRED>
<!ELEMENT policy permission (allow | deny) #REQUIRED>

<!ELEMENT obstacle (tag*,obstacle_environment+)>
<!ATTLIST obstacle name CDATA #REQUIRED>
<!ATTLIST obstacle originator CDATA #REQUIRED>
Expand Down
8 changes: 4 additions & 4 deletions cairis/config/sizes.json
Original file line number Diff line number Diff line change
Expand Up @@ -97,12 +97,12 @@
"theDescription" : 1000
},
"ClassAssociation" : {
"theHeadRole" : 50,
"theTailRole" : 50
"theHeadRole" : 200,
"theTailRole" : 200
},
"ClassAssociationParameters" : {
"theHeadRole" : 50,
"theTailRole" : 50
"theHeadRole" : 200,
"theTailRole" : 200
},
"Attacker" : {
"theName" : 50,
Expand Down
48 changes: 48 additions & 0 deletions cairis/controllers/ObjectController.py
Original file line number Diff line number Diff line change
Expand Up @@ -935,3 +935,51 @@ def delete(self,p1,p2,p3,p4,p5,p6):
resp = make_response(json_serialize(resp_dict, session_id=session_id), OK)
resp.contenttype = 'application/json'
return resp

class ObjectsByMethodAndFiveParametersAPI(Resource):
def __init__(self,**kwargs):
self.DAOModule = getattr(import_module('cairis.data.' + kwargs['dao']),kwargs['dao'])
self.thePathParameters = []
if 'get_method' in kwargs:
self.theGetMethod = kwargs['get_method']
if 'put_method' in kwargs:
self.thePutMethod = kwargs['put_method']
if 'del_method' in kwargs:
self.theDelMethod = kwargs['del_method']

def get(self,p1,p2,p3,p4,p5):
session_id = get_session_id(session, request)
dao = self.DAOModule(session_id)
pathValues = []
for parameterName,defaultValue in self.thePathParameters:
pathValues.append(request.args.get(parameterName,defaultValue))
objts = getattr(dao, self.theGetMethod)(p1,p2,p3,p4,p5,pathValues)
dao.close()
resp = make_response(json_serialize(objts, session_id=session_id), OK)
resp.contenttype = 'application/json'
return resp

def put(self,p1,p2,p3,p4,p5):
session_id = get_session_id(session, request)
dao = self.DAOModule(session_id)
pathValues = []
for parameterName,defaultValue in self.thePathParameters:
pathValues.append(request.args.get(parameterName,defaultValue))
objt = dao.from_json(request)
getattr(dao, self.thePutMethod)(objt,p1,p2,p3,p4,p5,pathValues)
resp_dict = {'message': p1 + '/' + p2 + '/' + p3 + '/' + p4 + '/' + p5 + ' updated'}
resp = make_response(json_serialize(resp_dict, session_id=session_id), OK)
resp.contenttype = 'application/json'
return resp

def delete(self,p1,p2,p3,p4,p5):
session_id = get_session_id(session, request)
dao = self.DAOModule(session_id)
pathValues = []
for parameterName,defaultValue in self.thePathParameters:
pathValues.append(request.args.get(parameterName,defaultValue))
getattr(dao, self.theDelMethod)(p1,p2,p3,p4,p5,pathValues)
resp_dict = {'message': p1 + '/' + p2 + '/' + p3 + '/' + p4 + '/' + p5 + ' deleted'}
resp = make_response(json_serialize(resp_dict, session_id=session_id), OK)
resp.contenttype = 'application/json'
return resp
4 changes: 3 additions & 1 deletion cairis/core/GoalEnvironmentProperties.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
__author__ = 'Shamal Faily'

class GoalEnvironmentProperties(EnvironmentProperties):
def __init__(self,environmentName,lbl='',definition='',category='',priority='',fitCriterion='',issue='',goalRefinements=[],subGoalRefinements=[],concs=[],cas=[]):
def __init__(self,environmentName,lbl='',definition='',category='',priority='',fitCriterion='',issue='',goalRefinements=[],subGoalRefinements=[],concs=[],cas=[], gp = None):
EnvironmentProperties.__init__(self,environmentName)
self.theLabel = lbl
self.theDefinition = definition
Expand All @@ -33,6 +33,7 @@ def __init__(self,environmentName,lbl='',definition='',category='',priority='',f
self.theSubGoalRefinements = subGoalRefinements
self.theConcerns = concs
self.theConcernAssociations = cas
self.thePolicy = gp

def label(self): return self.theLabel
def definition(self): return self.theDefinition
Expand All @@ -44,6 +45,7 @@ def goalRefinements(self): return self.theGoalRefinements
def subGoalRefinements(self): return self.theSubGoalRefinements
def concerns(self): return self.theConcerns
def concernAssociations(self): return self.theConcernAssociations
def policy(self): return self.thePolicy

def setDefinition(self,v): self.theDefinition = v
def setCategory(self,v): self.theCategory = v
Expand Down
71 changes: 68 additions & 3 deletions cairis/core/MySQLDatabaseProxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
from .GoalContribution import GoalContribution
from .TaskContribution import TaskContribution
from .UserStory import UserStory
from .PolicyStatement import PolicyStatement
from cairis.tools.PseudoClasses import RiskRating
import string
import os
Expand Down Expand Up @@ -586,6 +587,7 @@ def dimensionObject(self,constraintName,dimensionTable):
elif (dimensionTable == 'reference_contribution'): objts = self.getReferenceContributions(constraintId)
elif (dimensionTable == 'persona_implied_process'): objts = self.getImpliedProcesses(constraintId)
elif (dimensionTable == 'trust_boundary'): objts = self.getTrustBoundaries(constraintId)
elif (dimensionTable == 'policy_statement'): objts = self.getPolicyStatements(constraintId)
return (list(objts.values()))[0]


Expand Down Expand Up @@ -710,6 +712,9 @@ def getDimensionId(self,dimensionName,dimensionTable):
elif ((dimensionTable == 'provided_interface') or (dimensionTable == 'required_interface')):
cName,ifName = dimensionName.split('_')
rs = session.execute('select interfaceId(:name)',{'name':ifName})
elif (dimensionTable == 'policy_statement'):
psComponents = dimensionName.split('/')
rs = session.execute('select policyStatementId(:goal,:env,:subj,:at,:res)',{'goal':psComponents[0],'env':psComponents[1],'subj':psComponents[2],'at':psComponents[3],'res':psComponents[4]})
else:
rs = session.execute('call dimensionId(:name,:table)',{'name':dimensionName,'table':dimensionTable})

Expand Down Expand Up @@ -1759,6 +1764,9 @@ def addGoal(self,parameters):
self.addGoalRefinements(goalId,goalName,environmentName,environmentProperties.goalRefinements(),environmentProperties.subGoalRefinements())
self.addGoalConcerns(goalId,environmentName,environmentProperties.concerns())
self.addGoalConcernAssociations(goalId,environmentName,environmentProperties.concernAssociations())
gp = environmentProperties.policy()
if (gp != None):
self.addGoalPolicy(goalId,environmentName,gp['subject'],gp['access'],gp['resource'],gp['permission'])
return goalId

def updateGoal(self,parameters):
Expand All @@ -1782,6 +1790,9 @@ def updateGoal(self,parameters):
self.addGoalRefinements(goalId,goalName,environmentName,environmentProperties.goalRefinements(),environmentProperties.subGoalRefinements())
self.addGoalConcerns(goalId,environmentName,environmentProperties.concerns())
self.addGoalConcernAssociations(goalId,environmentName,environmentProperties.concernAssociations())
gp = environmentProperties.policy()
if (gp != None):
self.addGoalPolicy(goalId,environmentName,gp['subject'],gp['access'],gp['resource'],gp['permission'])

def getGoals(self,constraintId = -1):
goalRows = self.responseList('call getGoals(:id)',{'id':constraintId},'MySQL error getting goals')
Expand Down Expand Up @@ -1819,7 +1830,8 @@ def goalEnvironmentProperties(self,goalId):
goalRefinements,subGoalRefinements = self.goalRefinements(goalId,environmentId)
concerns = self.goalConcerns(goalId,environmentId)
concernAssociations = self.goalConcernAssociations(goalId,environmentId)
properties = GoalEnvironmentProperties(environmentName,goalLabel,goalDef,goalType,goalPriority,goalFitCriterion,goalIssue,goalRefinements,subGoalRefinements,concerns,concernAssociations)
gp = self.goalPolicy(goalId,environmentId)
properties = GoalEnvironmentProperties(environmentName,goalLabel,goalDef,goalType,goalPriority,goalFitCriterion,goalIssue,goalRefinements,subGoalRefinements,concerns,concernAssociations,gp)
environmentProperties.append(properties)
return environmentProperties

Expand Down Expand Up @@ -2406,9 +2418,14 @@ def addValueType(self,parameters):
vtDesc = parameters.description()
vtType = parameters.type()
vtScore = parameters.score()
if vtScore == '': vtScore = 0
if vtType == 'access_right' and vtScore == '':
vtScore = 1
elif vtScore == '':
vtScore = 0
else:
vtScore = int(vtScore)
if (vtType == 'access_right' and vtScore == 0):
raise DatabaseProxyException('Access right value cannot be set to 0')
vtRat = parameters.rationale()
if ((vtType == 'asset_value') or (vtType == 'threat_value') or (vtType == 'risk_class') or (vtType == 'countermeasure_value')):
exceptionText = 'Cannot add ' + vtType + 's'
Expand All @@ -2423,6 +2440,8 @@ def updateValueType(self,parameters):
envName = parameters.environment()
vtScore = parameters.score()
vtRat = parameters.rationale()
if (vtType == 'access_right' and vtScore == 0):
raise DatabaseProxyException('Access right value cannot be set to 0')
self.updateDatabase('call updateValueType(:id,:name,:desc,:type,:env,:score,:rat)',{'id':valueTypeId,'name':vtName,'desc':vtDesc,'type':vtType,'env':envName,'score':vtScore,'rat':vtRat},'MySQL error updating value type')

def getVulnerabilityDirectory(self,vulName = ''):
Expand Down Expand Up @@ -2681,7 +2700,12 @@ def candidateCountermeasurePatterns(self,cmId): return self.responseList('call c
def associateCountermeasureToPattern(self,cmId,patternName): self.updateDatabase('call associateCountermeasureToPattern(:cm,:pat)',{'cm':cmId,'pat':patternName},'MySQL error associating countermeasure to pattern')

def nameCheck(self,objtName,dimName):
objtCount = self.responseList('call nameExists(:obj,:dim)',{'obj':objtName,'dim':dimName},'MySQL error checking existence of ' + dimName + ' ' + objtName)[0]
objtCount = 0
if (dimName == 'policy_statement'):
goalName,envName,subjName,atName,resName = objtName.split('/')
objtCount = self.responseList('call policyStatementExists(:goal,:env,:subj,:at,:res)',{'goal':goalName,'env':envName,'subj':subjName,'at':atName,'res':resName},'MySQL error checking existence of ' + dimName + ' ' + objtName)[0]
else:
objtCount = self.responseList('call nameExists(:obj,:dim)',{'obj':objtName,'dim':dimName},'MySQL error checking existence of ' + dimName + ' ' + objtName)[0]
if (objtCount > 0): raise ARMException('Object with name ' + objtName + ' already exists.')


Expand Down Expand Up @@ -5066,3 +5090,44 @@ def storiesToXml(self,includeHeader=True):
def roleUserGoals(self,roleName):
return self.responseList('call roleUserGoals(:name)',{'name':roleName},'MySQL error getting user goals for role ' + roleName)

def goalPolicy(self,goalId,environmentId):
pData = self.responseList('call goalPolicy(:gId,:eId)',{'gId':goalId, 'eId':environmentId},'MySQL error getting goal policy')
if (len(pData) == 1):
return {'subject':pData[0][0],'access':pData[0][1],'resource':pData[0][2],'permission':pData[0][3]}
else:
return None

def addGoalPolicy(self,goalId,environmentName,subjName,acName,resName,pName):
self.updateDatabase('call addGoalPolicy(:gId,:eName,:subj,:acc,:res,:perm)',{'gId':goalId,'eName':environmentName,'subj':subjName,'acc':acName,'res':resName,'perm':pName},'MySQL error adding goal policy')

def addPolicyStatement(self,parameters):
psId = self.newId()
goalName = parameters.goal()
envName = parameters.environment()
subjName = parameters.subject()
atName = parameters.accessType()
resName = parameters.resource()
pName = parameters.permission()
self.updateDatabase('call addPolicyStatement(:id,:goal,:env,:subj,:at,:res,:perm)',{'id':psId,'goal':goalName,'env':envName,'subj':subjName,'at':atName,'res':resName,'perm':pName},'MySQL error adding policy statement')
return psId

def updatePolicyStatement(self,parameters):
psId = parameters.id()
goalName = parameters.goal()
envName = parameters.environment()
subjName = parameters.subject()
atName = parameters.accessType()
resName = parameters.resource()
pName = parameters.permission()
self.updateDatabase('call updatePolicyStatement(:id,:goal,:env,:subj,:at,:res,:perm)',{'id':psId,'goal':goalName,'env':envName,'subj':subjName,'at':atName,'res':resName,'perm':pName},'MySQL error updating policy statement')


def deletePolicyStatement(self,psId = -1):
self.deleteObject(psId,'policy_statement')

def getPolicyStatements(self,constraintId = -1):
psRows = self.responseList('call getPolicyStatements(:id)',{'id':constraintId},'MySQL error getting policy statements')
objts = []
for psId,goalName,envName,subjName,atName,resName,pName in psRows:
objts.append(PolicyStatement(psId,goalName,envName,subjName,atName,resName,pName))
return objts
37 changes: 37 additions & 0 deletions cairis/core/PolicyStatement.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.

__author__ = 'Shamal Faily'

class PolicyStatement:
def __init__(self,psId,goalName,envName,subjName,acName,resName,pName):
self.theId = psId
self.theGoalName = goalName
self.theEnvironmentName = envName
self.theSubject = subjName
self.theAccessType = acName
self.theResource = resName
self.thePermission = pName

def id(self): return self.theId
def goal(self): return self.theGoalName
def environment(self): return self.theEnvironmentName
def subject(self): return self.theSubject
def accessType(self): return self.theAccessType
def resource(self): return self.theResource
def permission(self): return self.thePermission
def name(self): return self.theGoalName + '/' + self.theEnvironmentName + '/' + self.theSubject + '/' + self.theAccessType + '/' + self.theResource
4 changes: 4 additions & 0 deletions cairis/daemon/main/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -363,6 +363,10 @@ def resetUser():
api.add_resource(ObjectController.ObjectByNameAPI, '/api/persona_characteristics/name/<path:name>',endpoint='persona_characteristic',resource_class_kwargs={'dao' : 'PersonaCharacteristicDAO'})
api.add_resource(ObjectController.ObjectsSummaryAPI, '/api/persona_characteristics/summary',endpoint='personacharacteristicssummary',resource_class_kwargs={'dao' : 'PersonaCharacteristicDAO'})

# Policy Statement routes
api.add_resource(ObjectController.ObjectsAPI, '/api/policy_statements',endpoint='policy_statements',resource_class_kwargs={'dao': 'PolicyStatementDAO'})
api.add_resource(ObjectController.ObjectsByMethodAndFiveParametersAPI,'/api/policy_statements/goal/<path:p1>/environment/<path:p2>/subject/<path:p3>/access_type/<path:p4>/resource/<path:p5>',endpoint='policy_statement',resource_class_kwargs={'dao' : 'PolicyStatementDAO', 'get_method' : 'get_object_by_name', 'put_method' : 'update_object', 'del_method' : 'delete_object'})

# Project routes
api.add_resource(ObjectController.ObjectsByMethodAPI, '/api/settings',endpoint='project_settings',resource_class_kwargs={'dao' : 'ProjectDAO','get_method' : 'get_settings','put_method' : 'apply_settings'})
api.add_resource(ObjectController.ObjectsByMethodAPI, '/api/settings/clear',endpoint='project_clear', resource_class_kwargs={'dao' : 'ProjectDAO', 'post_method' : 'clear_project'})
Expand Down
Loading

0 comments on commit 72aea65

Please sign in to comment.