diff --git a/README.md b/README.md index 8f54884..2345940 100644 --- a/README.md +++ b/README.md @@ -1,124 +1,5 @@ -# Users: -* Admin - Access to everything -* Manager - Manage Permission to Machines with same Letter (A, B, C) -* Maker - Use Permission to Machines with same Letter (A, B, C) -* Guest - Disclose Permission only for all Machines +# API-Testsetup, aber mit Docker -## Password -Password for all Users is: `secret` +wirklich nur um das API zu testen. ATM implementiert: machines::* & machine::read, authenticate -## List of Users -``` -Admin1 -Admin2 - -ManagerA1 -ManagerA2 -ManagerB1 -ManagerB2 -ManagerC1 -ManagerC2 -ManagerABC1 -ManagerABC2 - -MakerA1 -MakerA2 -MakerB1 -MakerB2 -MakerC1 -MakerC2 -MakerACB1 -MakerACB2 -MakerACB3 - -GuestA1 -GuestA2 -GuestB1 -GuestB2 -GuestC1 -GuestC2 -GuestACB1 -GuestACB2 - -MakerQRA -MakerQRB -MakerQRC -``` - -# Machines -Machines have all a Dummy Actor - -## List of Categories -``` -CategoryA -CategoryB -CategoryC -``` - -## List of Machines -``` -MachineA1 -MachineA2 -MachineA3 -MachineA4 -MachineA5 - -MachineB1 -MachineB2 -MachineB3 -MachineB4 -MachineB5 - -MachineC1 -MachineC2 -MachineC3 -MachineC4 -MachineC5 -``` - -# Roles -All Roles have only one Permission -Users have multipile Roles to give them access -`TestEnv.Admin` have all Permissions - -## List of Roles -``` -Admin - -ManageA -ManageB -ManageC - -UseA -UseB -UseC - -ReadA -ReadB -ReadC - -DiscloseA -DiscloseB -DiscloseC -``` - -## List of Permissions -``` -TestEnv.Admin - -TestEnv.Manage.A -TestEnv.Manage.B -TestEnv.Manage.C - -TestEnv.Write.A -TestEnv.Write.B -TestEnv.Write.C - -TestEnv.Read.A -TestEnv.Read.B -TestEnv.Read.C - -TestEnv.Disclose.A -TestEnv.Disclose.B -TestEnv.Disclose.C -``` +* run `docker-compose up` in this directory \ No newline at end of file diff --git a/adapters/actor.py b/adapters/actor.py new file mode 100755 index 0000000..489260c --- /dev/null +++ b/adapters/actor.py @@ -0,0 +1,179 @@ +#!/usr/bin/env python3 + +import sys +import argparse + +def on_free(args, actor_name): + """ + Function called when the state of the connected machine changes to Free + again + """ + if args.verbose > 2: + print("on_free called!") + + if actor_name == "DoorControl1": + # Do whatever you want to do in case `DoorControl1` is returned back to free. + # Keep in mind that process actors should return quickly to not miss + # updates, so if you need to do things that take a while fork a new + # process e.g. with the `subprocess` Module + print("I'm locking door 1!") + pass + elif actor_name == "DoorControl2": + print("I'm locking door 2!") + pass # Close a different door + else: + if not args.quiet: + print("process called with unknown id %s for state `Free`" % actor_name) + # It's a good idea to exit with an error code in case something + # unexpected happens. + # The process module logs everything printed to stdout by actors into + # the server log, but marks them as `Error` in case the actor process + # exits with a code != 0, making debugging somewhat easier. + exit(-1) + +def on_use(args, actor_name, user_id): + """ + Function called when an user takes control of the connected machine + + user_id contains the UID of the user now using the machine + """ + if args.verbose > 2: + print("on_use called!") + if actor_name == "DoorControl1": + print("I'm opening door 1 for 10 seconds!") + pass # Open door one + elif actor_name == "DoorControl2": + print("I'm opening door 2 for 10 seconds!") + pass # Open a different door + else: + if not args.quiet: + print("process called with unknown id %s for state `InUse`" % actor_name) + # It's a good idea to exit with an error code in case something + # unexpected happens. + # The process module logs everything printed to stdout by actors into + # the server log, but marks them as `Error` in case the actor process + # exits with a code != 0, making debugging somewhat easier. + exit(-1) + +def on_tocheck(args, actor_name, user_id): + """ + Function called when an user returns control and the connected machine is + configured to go to state `ToCheck` instead of `Free` in that case. + + user_id contains the UID of the manager expected to check the machine. + The user that used the machine beforehand has to be taken from the last + user field using the API (via e.g. the mobile app) + """ + if args.verbose > 2: + print("on_tocheck called!") + if not args.quiet: + print("process called with unexpected combo id %s and state 'ToCheck'" % actor_name) + exit(-1) + +def on_blocked(args, actor_name, user_id): + """ + Function called when an manager marks the connected machine as `Blocked` + + user_id contains the UID of the manager that blocked the machine + """ + if args.verbose > 2: + print("on_blocked called!") + if not args.quiet: + print("process called with unexpected combo id %s and state 'Blocked'" % actor_name) + exit(-1) + +def on_disabled(args, actor_name): + """ + Function called when the connected machine is marked `Disabled` + """ + if not args.quiet: + print("process called with unexpected combo id %s and state 'Disabled'" % actor_name) + exit(-1) + +def on_reserve(args, actor_name, user_id): + """ + Function called when the connected machine has been reserved by somebody. + + user_id contains the UID of the reserving user. + """ + if not args.quiet: + print("process called with unexpected combo id %s and state 'Reserved'" % actor_name) + exit(-1) + + +def main(args): + """ + Python example actor + + This is an example how to use the `process` actor type to run a Python script. + """ + + if args.verbose is not None: + if args.verbose == 1: + print("verbose output enabled") + elif args.verbose == 2: + print("loud output enabled!") + elif args.verbose == 3: + print("LOUD output enabled!!!") + elif args.verbose > 4: + print("Okay stop you're being ridiculous.") + sys.exit(-2) + else: + args.verbose = 0 + + # You could also check the actor name here and call different functions + # depending on that variable instead of passing it to the state change + # methods. + + new_state = args.state + if new_state == "free": + on_free(args, args.name) + elif new_state == "inuse": + on_use(args, args.name, args.userid) + elif new_state == "tocheck": + on_tocheck(args, args.name, args.userid) + elif new_state == "blocked": + on_blocked(args, args.name, args.userid) + elif new_state == "disabled": + on_disabled(args, args.name) + elif new_state == "reserved": + on_reserve(args, args.name, args.userid) + else: + print("Process actor called with unknown state %s" % new_state) + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + # Parameters are passed to the Process actor as follows: + # 1. the contents of params.args, split by whitespace as separate args + # 2. the configured id of the actor (e.g. "DoorControl1") + # 3. the new state as one of [free|inuse|tocheck|blocked|disabled|reserved] + + parser.add_argument("-q", "--quiet", help="be less verbose", action="store_true") + parser.add_argument("-v", "--verbose", help="be more verbose", action="count") + + parser.add_argument("name", + help="name of this actor as configured in bffh.dhall" + ) + + # We parse the new state using subparsers so that we only require a userid + # in case it's a state that sets one. + subparsers = parser.add_subparsers(required=True, dest="state") + + parser_free = subparsers.add_parser("free") + + parser_inuse = subparsers.add_parser("inuse") + parser_inuse.add_argument("userid", help="The user that is now using the machine") + + parser_tocheck = subparsers.add_parser("tocheck") + parser_tocheck.add_argument("userid", help="The user that should go check the machine") + + parser_blocked = subparsers.add_parser("blocked") + parser_blocked.add_argument("userid", help="The user that marked the machine as blocked") + + parser_disabled = subparsers.add_parser("disabled") + + parser_reserved = subparsers.add_parser("reserved") + parser_reserved.add_argument("userid", help="The user that reserved the machine") + + args = parser.parse_args() + main(args) diff --git a/adapters/actor.sh b/adapters/actor.sh new file mode 100755 index 0000000..704c66f --- /dev/null +++ b/adapters/actor.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +echo "Bash actor called with $@" > /tmp/act +echo "Bash actor called with: $@" diff --git a/adapters/fail-actor.sh b/adapters/fail-actor.sh new file mode 100755 index 0000000..5630f1c --- /dev/null +++ b/adapters/fail-actor.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash + +echo "This is some error output" > /dev/stderr +exit 115 diff --git a/bffh.dhall b/config/bffh/bffh.dhall similarity index 99% rename from bffh.dhall rename to config/bffh/bffh.dhall index e27565e..fcb5e92 100644 --- a/bffh.dhall +++ b/config/bffh/bffh.dhall @@ -25,8 +25,8 @@ ], -- Configure TLS. BFFH requires a PEM-encoded certificate and the associated key as two separate files - certfile = "/etc/bffh/cert.pem", - keyfile = "/etc/bffh/key.pem", + certfile = "/etc/letsencrypt/cert.pem", + keyfile = "/etc/letsencrypt/key.pem", -- BFFH right now requires a running MQTT broker. mqtt_url = "tcp://mqtt:1883", diff --git a/users.toml b/config/bffh/users.toml similarity index 100% rename from users.toml rename to config/bffh/users.toml diff --git a/config/cert/cert.pem b/config/cert/cert.pem new file mode 100644 index 0000000..f771f32 --- /dev/null +++ b/config/cert/cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFYzCCA0ugAwIBAgIUD/WP9/ClkcITVEE1ApyenpySXkswDQYJKoZIhvcNAQEL +BQAwQTELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwGQmVy +bGluMRAwDgYDVQQKDAdSTEtNIFVHMB4XDTIyMDQyMDEzNTk1MFoXDTIzMDQyMDEz +NTk1MFowQTELMAkGA1UEBhMCREUxDzANBgNVBAgMBkJlcmxpbjEPMA0GA1UEBwwG +QmVybGluMRAwDgYDVQQKDAdSTEtNIFVHMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAtlDacP0s0CjC5mP7pe2/uAo7nrP2WHztnG9ougbAcmSnmOCNWxYo +3ItGZQ4morGqTndx1yrr7/ZXVmqvvxtbcwQc99u4KFw9DrzCr/5la5SJv/KsBOW4 +mjNNPJY79DKsULuOo6nqZGUFNhk+nbFSjMy684zsIvj6YNeYE4lvPGVtQ+buBlep +FjYwyFgezpbdYnVPNKCCEag3Pgxi2Sxys9vaaUIP/BpMrLXXARk5sFHV5kiQRRZ6 +mw7hQz9Sb7BbQHeH1ejTLUNSTpHZ5fdptVTQRwt2Er5FgLcBPwckGymOCSsg8Bop +N6zFutybVl0vYK0KkslADLo+S8/W81ckKpUYFnk0zw9ET8LlrMnzc9jfV5BMtijz +sKArOC/ALLXz5FiPfpq+vVpqy354YkIy+n4xBKYpp9s3xeBpMLgupL/Tx7yB9Dxs +9Dp0vzDnx6UDHHo+U9OZYTmjy2oFxhM3lN73Hs2L2zgmWYUgksCQYJOUcXtGUW6C +nYLiSDJPqBoFSVGlUVSf9Aq4h23OWyRPD8GKcMQXVdFUEckgf5BRpGkxDigsDaAu +uN0QHCPw3fTg69xmIt0PxWGy+bEFSPZd83CtnklOAXTv7EnHb0HtZ1fDSqvbcGIi +A5LaCitC4Z5IaU7Ub23AY8BcjLnRopPIOVLrLvmznCoy0ntLBht/Z/0CAwEAAaNT +MFEwHQYDVR0OBBYEFOJ3+fyj1u6eou6MOktC5vUG2JPVMB8GA1UdIwQYMBaAFOJ3 ++fyj1u6eou6MOktC5vUG2JPVMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggIBAE0eleTJs87FJ9Kuex/8NNZXs+4OjqetPbIJV32+IvIht1c51Bbo0MrS +7RdE4MIj5XyC6vpk+vpb/rnFr8Q655J7Ao/iVhwIW9k8Y4uJL5YvIrJyM9w/JWNa +Jp2f5Jc0xJmKaU7rkegokosg7y7vJGz+l2oeWcBFf6BQ/zcifUFGTah0u0qe2vGR +9dFZ07CAqawFvLsg/xDwmXkhEVWjB9CmwbbH5fgd9fpBL8wGiraaVCiVSwun9jzn +ylBCWF24BoI5UAjHgbPDAqwkbTLJaDPZF52AOT9M6UY9naJ8PflykwIqvAejZvbi +CrfUjqXS2F387VGJ9/xxzM2ZeMjWXT+FjOKJAZBf4r5CjsUvpBQZw/LiHfKzzTos +VauB6qJhIcqUUUpFdKeeyGkExfxsCuHfTk8n2g3kCYZUpgKt55gmFGUMqP8qXSko +6BfGIEtIEHdBdb5++IBIXINMj7mLYimk/iQkGWwQTN3RXCck6yN5lzUNNQ81Ea97 +dj4/UAzf9mztNVmZJMZ/sqVxUciGy+kr6JJi/4pUGIZh5IezHY5bS4dRAN0mQFzz +aYkyZlGrVrvex7zBeyO88erMnFMxFS1el9ms0Izu85NmkryWkg+U7yzJAFqJXDHT +an1Se25jGeyqyA0Y2soZ9GjxkTkOkXuPIYr+LdZPpd8ce0KI5ncg +-----END CERTIFICATE----- diff --git a/config/cert/key.pem b/config/cert/key.pem new file mode 100644 index 0000000..9b64f24 --- /dev/null +++ b/config/cert/key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 ++cqdvrc3lDTZ3QIesrwgLuCGSQpj +-----END PRIVATE KEY----- diff --git a/config/mosquitto/mosquitto.conf b/config/mosquitto/mosquitto.conf new file mode 100644 index 0000000..d33a1a7 --- /dev/null +++ b/config/mosquitto/mosquitto.conf @@ -0,0 +1,3 @@ +persistence true +persistence_location /mosquitto/data/ +log_dest file /mosquitto/log/mosquitto.log \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..bb8180e --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,39 @@ +version: "3.8" +services: + #dnsrobocert: + # image: adferrand/dnsrobocert + # pull_policy: always + # restart: always + # volumes: + # - "./config/cert:/etc/letsencrypt" + # - "./config/dnsrobocert:/etc/dnsrobocert" + + bffh: + image: registry.gitlab.com/fabinfra/fabaccess/bffh:v0.3-pre + pull_policy: always + restart: always + ports: + - "59666:59661" + entrypoint: ["sh", "-c", "bffhd -c /etc/bffh/bffh.dhall --load=/etc/bffh/users.toml; bffhd -c /etc/bffh/bffh.dhall"] + environment: + - "RUST_LOG=debug" + volumes: + # generate a sample config.toml by running "docker run registry.gitlab.com/fabinfra/fabaccess/bffh:dev-latest --print-default > examples/config.toml" from the project root. You may have to delete the ipv6 listen section. + - "./config/bffh:/etc/bffh" + - "./adapters:/usr/local/lib/bffh/adapters" + - "./config/cert:/etc/letsencrypt" + - data:/var/lib/bffh + links: + - mqtt + + mqtt: + image: eclipse-mosquitto:1.6.15 + restart: always + ports: + - "1883:1883" + volumes: + - "./config/mosquitto/mosquitto.conf:/mosquitto/config/mosquitto.conf" + +volumes: + data: +