Simple Python generator for security- and privacy-enhanced web applications.
NuActionGUI is a model-driven methodology for developing secure applications. It enables developers to specify both security and privacy requirements at a high level using formal models. From these models, web applications are automatically generated.
Unlike conventional development tools, NuActionGUI offers a precise semantics, making it possible to verify security and privacy guarantees through formal analysis. This ensures that applications behave as intended and comply with regulatory requirements, such as the GDPR.
NuActionGUI is developed by the Institute for Information Security at ETH Zurich, Switzerland.
For more information about NuActionGUI, please send an email to hoang.nguyen@inf.ethz.ch.
NuActionGUI is licensed for non-commercial use under the following License Agreement.
NuActionGUI implements a specific instance of the model-driven security and privacy methodology. The design modeling language used is a subset of the ComponentUML model, combining its metamodel with SecureUML and PrivateUML, and exposing a textual concrete notation. It enables the generation of data-centric web applications that enforce fine-grained access control, purpose limitation, and data-subject consent privacy policies. The modeling languages in NuActionGUI includes:
NuActionGUI provides both modeling primitives and model transformations to specify and automatically generate the resulting web application.
For more details, please refer to the following research paper.
The data model defines the state space of the application. One can think of it as defining the classes and attributes in an object-oriented programming language like Java or C++.
The NuActionGUI language for modeling application domains is a textual language, which provides a subset of the ComponentUML metamodel, which is in turn a subset of the UML class diagram. In particular, the main modeling elements of the NuActionGUI data model language are:
entity keyword.
Attributes, association-ends, and methods are declared within the entity's declaration, enclosed in brackets.Boolean, Integer, String, another entity, an enumerated type, or a Set/Bag of these types.oppositeTo).
Multiplicity can be 0..* or 0..1.enum keyword. Values are listed within the declaration, enclosed in brackets.@entry as prefix.
grammar DataModel;
dataModel: (components)+;
components: component (components)?;
component:
entity # EntityComponent
| enumm # EnumComponent
;
entity: 'entity' TypeName '{' (entityBody)? '}';
entityBody: property entityBody?;
property:
propertyType propertyName # Attribute
| propertyType propertyName ('oppositeTo' propertyName | 'in' TypeName) # End
| ('@entry')? (retType = propertyType)? propertyName
'(' (argTypes += propertyType argName += propertyName
(',' argTypes += propertyType argName += propertyName)* )? ')' # Method
;
propertyType: collectionType | basicType;
collectionType: collectionTypeName '(' propertyType ')';
basicType: primitiveTypeName | TypeName;
enumm: 'enum' TypeName '{' enumBody '}';
enumBody: (EnumLiteral | TypeName) enumBody?;
TypeName: [A-Z][a-z_0-9]*;
EnumLiteral: [A-Z][A-Z_0-9]*;
propertyName: ID;
collectionTypeName:
'Bag'
| 'OrderedSet'
| 'Sequence'
| 'Set'
;
primitiveTypeName:
'String'
| 'Integer'
| 'Real'
| 'Boolean'
;
ID: [a-zA-Z_][a-zA-Z_0-9]*;
WS: [ \t\n\r]+ -> skip;
COMMENT: '//' ~[\r\n]* -> skip;
entity Person {
String name
String email
Role role
Set(Post) posts oppositeTo author
@entry getFeeds()
recommendedPosts()
}
entity Post {
String title
String content
Person author oppositeTo posts
}
enum Role {
ADMIN
EDITOR
VIEWER
}
A security model defines the application’s authorization policy in terms of allowed actions on the resources provided by the data model. The νActionGUI language for modeling the application’s security is a textual language that provides the following elements:
Role followed by the role’s name and its permissions. At most one permission per entity from the underlying data model may be declared.action(subresource) [constraint] where subresource can be the attribute or association end of the entity whose permission is grouped under, and constraint is an Object Constraint Language (OCL) formula. If the subresource is omitted, the action is a composite action that applies to all subresources. If the constraint is omitted, it is assumed to be the true OCL expression.anonymous before a role name declares that this is the role of unauthenticated users.default before a role name declares that this is the role a user gets once they register to the application.extends followed by an existing role after a role name specifies role inheritance.
grammar SecurityModel;
import OclExpression;
securityModel: userClass (roles)+;
userClass: 'USER' ResourceName;
roles: (srole | role) (roles)?;
srole: ('default' | 'anonymous') role;
role: 'Role' RoleName ('extends' RoleName)? '{' (resources | permissions)? '}';
resources: resource (resources)?;
resource: ResourceName '{' (permissions)? '}';
permissions:
actions (permissions)? #ActionUnconstrained
| actions constraint (permissions)? #ActionConstrained
;
actions: action (',' actions)?;
action:
ActionType #ActionResource
| ActionType ('(' attributeName ')') #ActionAttribute
;
constraint: '[' oclExp ']';
RoleName: [A-Z][A-Z_0-9]+;
ActionType:
'fullAccess'
| 'create'
| 'delete'
| 'read'
| 'update'
| 'add'
| 'remove'
| 'execute'
;
ResourceName: [A-Z][a-z_0-9]*;
attributeName: ID;
ID: [a-zA-Z_][a-zA-Z_0-9]*;
WS: [ \t\n\r]+ -> skip;
USER Person
anonymous Role VIEWER {
Person {
read
}
Post {
read
}
}
default Role EDITOR extends VIEWER {
Person {
update(name) [self = caller]
}
Post {
create
read
update(title) [self.author = caller]
update(content) [self.author = caller]
delete [self.author = caller]
}
}
Role ADMIN extends EDITOR {
Person {
create
update(role)
delete
}
Post {
fullAccess
}
}
A privacy model identifies an application’s personal data and purposes. It declares the purposes for which personal data will be used and under what conditions, and associates data model methods with purposes. νActionGUI performs purpose-based access control based on the privacy model: any action performed on personal data within a method is checked by comparing the method’s (actual) purpose to the data’s (declared) purpose, and by considering the data owner’s consent for the declared purposes.
The privacy model contains the following elements:
Resource.subresource syntax.includes keyword and a list of purposes is a complex purpose.Resource.method purpose.Resource.subresource purpose [constraint] <description>, where constraint is an OCL formula and description is a string describing it. Both can be omitted (defaulting to true and an empty string).
grammar PrivacyModel;
import OclExpression;
privacyModel: personaldata purposes apurposes dpurposes;
personaldata: 'Personal data' '{' resources? '}';
resources: ResourceName ('.' ms+=methodName)? (',' resources)?;
purposes: 'Purposes' '{' purpose? '}';
purpose:
PurposeName (',' purpose)? #SimplePurpose
| PurposeName 'includes' (pss += PurposeName)+ (',' purpose)? #ComplexPurpose
;
apurposes: 'Actual purposes' '{' apurpose? '}';
apurpose: ('main' PurposeName | ResourceName '.' methodName PurposeName) (',' apurpose)?;
dpurposes: 'Declared purposes' '{' dpurpose? '}';
dpurpose: rs+=ResourceName ('.' ms+=methodName)? (',' rs+=ResourceName ('.' ms+=methodName)?)* (constraint desc)? PurposeName (',' dpurpose)?;
PurposeName: [A-Z][A-Z_0-9]+;
ResourceName: [A-Z][a-z_0-9]*;
methodName: ID;
constraint: '[' oclExp ']';
desc: '<' (words+=ID)+ '>';
ID: [a-zA-Z_][a-zA-Z_0-9]*;
WS: [ \t\n\r]+ -> skip;
Personal data {
Person.name,
Person.email
}
Purposes {
MARKETING,
DISPLAY,
ANY includes MARKETING DISPLAY
}
Actual purposes {
Person.getFeeds DISPLAY,
Person.recommendedPosts MARKETING
}
Declared purposes {
Person.name, Person.email DISPLAY,
Person.name MARKETING [self.posts.size() > 0] <has at least one post>,
Person.email MARKETING
}
docker compose up
nag-app container instance.docker exec -it nag-app bash
python3 -m venv .venv source .venv/bin/activate
pip install -r requirements.txt
make clean make grammars
make grammars, you may be prompted to install Java JRE:Downloading antlr4-4.13.2-complete.jar ANTLR tool needs Java to run; install Java JRE 11 yes/no (default yes)?
pip install ./ocl-py
make test
Once the environment is set up, you can use the NuActionGUI CLI to generate web applications from your models.
python3 generate.py -p <project_folder> -o project
python3 generate.py -p <project_folder> -o project -re
/app/project/<project_folder>/instance/.cd /app/project/<project_folder>
flask --app app.py run --host=0.0.0.0
localhost:5000.Copyright Institute for Information Security, ETH Zurich
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
OCL-py is a Python implementation of the Object Constraint Language (OCL).
git clone https://gitlab.inf.ethz.ch/skrstic/ocl-py.git cd ocl-py pip install . cd ..
cd src pip install -r requirements.txt
make grammars
make test