Simple Python generator for security- and privacy-enhanced web applications.
νActionGUI is a model-driven methodology for developing secure applications. It enables developers to specify both access control and data protection requirements at a high level using formal models. From these models, web applications are generated automatically.
Unlike conventional development tools, νActionGUI has a precise semantics, making it possible to validate security and privacy guarantees through formal model analysis. This ensures that applications behave as intended and comply with regulatory requirements such as the GDPR.
νActionGUI is developed by the Institute of Information Security at ETH Zurich, Switzerland.
For questions about νActionGUI, please contact Hoang Nguyen at hoang.nguyen@inf.ethz.ch.
νActionGUI is licensed for non-commercial use under the following license agreement.
νActionGUI is supported by the Swiss National Science Foundation (SNSF) under the project Model-driven Security & Privacy (grant no. 204796).
We thank the following people for their contributions to improving the tool's expressiveness and validation aspects:
νActionGUI 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 νActionGUI includes:
νActionGUI provides both modeling primitives and model transformations to specify and automatically generate the resulting web application.
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 νActionGUI 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 νActionGUI 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
}
If you use νActionGUI in your research, please cite the following work:
Srđan Krstić, Hoàng Nguyễn, David Basin
Proceedings on Privacy Enhancing Technologies (PoPETs), 2024(1), pp. 314–329
Hoàng Nguyễn
Doctoral dissertation, ETH Zurich
To appear
The following student projects and theses contributed to the development of νActionGUI:
Nasr Raymond
Semester project, Institute of Information Security, ETH Zurich, 2024
Daniel Gradwohl
Bachelor's thesis, Institute of Information Security, ETH Zurich, 2024
Andrei Cotor
Semester project, Institute of Information Security, ETH Zurich, 2026
νActionGUI is distributed as a source package. Download the archive below, then follow the Installation & Usage instructions to build and run it.
⇩ Download νActionGUI (source, .zip)
The archive contains the generator, the OCL-py library, the bundled VS Code extension (tooling/vscode-nag), and an example project. It is released under the MIT License. Building the model parsers requires a Java runtime (for ANTLR); see Installation & Usage.
v1.2.0 — Current release
nuactiongui command-line tool, replacing the previous python script.-re), which rebuilds the security and privacy enforcement while preserving the rest of the generated application.v2.0.0 — Upcoming
execute and execute* permissions for class methods. The execute* permission bypasses the remaining checks once authorization succeeds.self parameter and constructor-based initialization.init action has been added, together with a full action hierarchy.Set, OrderedSet, Bag, and List.
v1.1.0 — Second stable release
v1.0.0 — First stable release
v0.0.1 — Prototype
The quickest way is the bundled Docker container, which ships with all dependencies, the model parsers, and the nuactiongui command pre-installed.
docker compose up --build --detach
nuactiongui.docker exec -it nuactiongui bash
python3 -m venv .venv source .venv/bin/activate
pip install -r requirements.txt
make clean && make grammars
pip install ./ocl-py pip install -e .
nuactiongui command.Once installed, the nuactiongui command generates web applications from your models. Model and output paths are resolved relative to the current directory.
.dtm, .stm, and .ptm models) in a subdirectory of examples/, then run:
nuactiongui -p <project_folder> -i examples -o output
nuactiongui -p EventPlatform -i examples -o output. The generated app is written to output/<project_folder>.nuactiongui -p <project_folder> -i examples -re
output/<project_folder>/instance/ before running again.cd output/<project_folder>
flask --app app.py run --host=0.0.0.0
localhost:5000. This is a development server — do not use it in production.Copyright Institute of 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.