diff options
-rw-r--r-- | README.md | 14 | ||||
-rw-r--r-- | auth-server-poc/src/app.py | 3 | ||||
-rw-r--r-- | auth-server-poc/userdb.yaml (renamed from auth-server-poc/src/userdb.yaml) | 6 | ||||
-rwxr-xr-x | quickstart.sh | 7 | ||||
-rwxr-xr-x | src/main.py | 17 | ||||
-rwxr-xr-x | src/quickstart_test.sh | 5 | ||||
-rw-r--r-- | src/test/test_api.py | 4 | ||||
-rw-r--r-- | tools/jwt_producer.py | 64 |
8 files changed, 86 insertions, 34 deletions
@@ -81,7 +81,13 @@ We can also limit the number of results and skip N results forward with the para curl -s -H "Authorization: Bearer $JWT" 'http://localhost:80/sc/v0/get?limit=5&skip=2' | json_pp -json_opt utf8,pretty -There is also a convenience script `do-as` which simplifies performing actions as a particular user. +## Tips and tricks + +There is a convenience script `do-as` which simplifies performing actions as a particular user. + +You can decode a JWT using jq by piping to `jq -r '.access_token | split(".") | .[0],.[1] | @base64d' | jq`. Full example: + + curl http://localhost:8000/api/v1.0/auth -X POST -p -u user1:pwd | jq -r '.access_token | split(".") | .[0],.[1] | @base64d' | jq ## Development @@ -91,9 +97,3 @@ There are two docker-compose files used for development: - `auth-server-poc/docker-compose.yml` for the JWT server. To apply changes, `source env-vars.sh` and do e.g. `docker-compose -f docker/docker-compose-dev.yaml up -d --build collector`. - -## JWT mechanics (work in progress) - -2021-11-24: Currently no checks except that the JWT is valid are performed when -adding observations. When retrieving observations, the JWTs "domains" claim is -used. In auth-server-poc, domains is hard-coded to `["sunet.se"]` as an example. diff --git a/auth-server-poc/src/app.py b/auth-server-poc/src/app.py index c7ba0d1..37a7030 100644 --- a/auth-server-poc/src/app.py +++ b/auth-server-poc/src/app.py @@ -16,6 +16,7 @@ jwt = JWTManager(app) PEM_PRIVATE = "/opt/auth-server-poc/cert/private.pem" PEM_PUBLIC = "/opt/auth-server-poc/cert/public.pem" +USERDB_YAML = "/opt/auth-server-poc/userdb/userdb.yaml" app.config["JWT_PRIVATE_KEY"] = open(PEM_PRIVATE).read() app.config["JWT_PUBLIC_KEY"] = open(PEM_PUBLIC).read() @@ -28,7 +29,7 @@ class AuthApi(Resource): def post(self): identity = request.environ.get("REMOTE_USER") - db = authn.UserDB("userdb.yaml") + db = authn.UserDB(USERDB_YAML) additional_claims = { "type": "access", "read": db.read_perms(identity), diff --git a/auth-server-poc/src/userdb.yaml b/auth-server-poc/userdb.yaml index c55773b..937328c 100644 --- a/auth-server-poc/src/userdb.yaml +++ b/auth-server-poc/userdb.yaml @@ -1,3 +1,9 @@ +usr: + authz: + sunet.se: rw + su.se: rw + kth.se: rw + user1: authz: sunet.se: r diff --git a/quickstart.sh b/quickstart.sh index edf8c43..950475b 100755 --- a/quickstart.sh +++ b/quickstart.sh @@ -22,12 +22,17 @@ fi # Generate a default htpasswd file with a user "usr:pwd". if [ ! -f ${DOCKER_JWT_HTPASSWD_PATH}/.htpasswd ]; then - htpasswd -b -c ${DOCKER_JWT_HTPASSWD_PATH}/.htpasswd user1 pwd + htpasswd -b -c ${DOCKER_JWT_HTPASSWD_PATH}/.htpasswd usr pwd + htpasswd -b ${DOCKER_JWT_HTPASSWD_PATH}/.htpasswd user1 pwd htpasswd -b ${DOCKER_JWT_HTPASSWD_PATH}/.htpasswd user2 pwd htpasswd -b ${DOCKER_JWT_HTPASSWD_PATH}/.htpasswd user3 pwd htpasswd -b ${DOCKER_JWT_HTPASSWD_PATH}/.htpasswd user4 pwd fi +if [ ! -f ${DOCKER_JWT_HTPASSWD_PATH}/userdb.yaml ]; then + cp auth-server-poc/userdb.yaml ${DOCKER_JWT_HTPASSWD_PATH}/userdb.yaml +fi + # Launch the containers. docker-compose -f docker/docker-compose-dev.yaml up -d docker-compose -f auth-server-poc/docker-compose.yml up -d diff --git a/src/main.py b/src/main.py index a65971d..d6f420f 100755 --- a/src/main.py +++ b/src/main.py @@ -31,6 +31,23 @@ async def mock_x_total_count_header(request: Request, call_next): response.headers["X-Total-Count"] = "100" return response +<< << << < HEAD +== == == = +for i in range(10): + try: + db = DictDB() + except Exception: + print( + f'Database not responding, will try again soon. Attempt {i + 1} of 10.') + else: + break + time.sleep(1) +else: + print('Database did not respond after 10 attempts, quitting.') + sys.exit(-1) + +>>>>>> > main + def get_pubkey(): try: diff --git a/src/quickstart_test.sh b/src/quickstart_test.sh index e81024f..3d4945e 100755 --- a/src/quickstart_test.sh +++ b/src/quickstart_test.sh @@ -5,7 +5,6 @@ export COUCHDB_PASSWORD=test export DOCKER_JWT_PUBKEY_PATH="`pwd`/test/unittest_cert/" export JWT_PUBKEY_PATH="`pwd`/test/unittest_cert/public.pem" -export JWT_TOKEN="eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJ0eXBlIjoiYWNjZXNzIiwiZG9tYWlucyI6WyJzdW5ldC5zZSJdfQ._emWyVw-6qer5u65SitS8bZJas7l8bw4almnI1TB7DBnzNsch8ctU4btlgBpfJ2jbrvXZTIl8jXIcykO4crUrQ" virtualenv=no couchdb=no @@ -49,8 +48,8 @@ mkdir test/unittest_cert cat <<EOF > test/unittest_cert/public.pem -----BEGIN PUBLIC KEY----- -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEPW8bkkVIq4BX8eWwlUOUYbJhiGDv -K/6xY5T0BsvV6pbMoIUfgeThVOq5I3CmXxLt+qyPska6ol9fTN7woZLsCg== +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGHX8ipqVWtr49TXyX0f/L4GPhEpg +N0Erzy7hHkXVrkgKpnHSRLYWgbW4rscLoJAJeEv7Be5iH0TM8l09w8Q3wQ== -----END PUBLIC KEY----- EOF diff --git a/src/test/test_api.py b/src/test/test_api.py index cabe101..9d76e5e 100644 --- a/src/test/test_api.py +++ b/src/test/test_api.py @@ -9,9 +9,7 @@ from fastapi import FastAPI from fastapi import testclient client = testclient.TestClient(app) -JWT_TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJ0eXBlIjoiYWNjZXNzIiwi' + \ - 'ZG9tYWlucyI6WyJzdW5ldC5zZSJdfQ._emWyVw-6qer5u65SitS8bZJas7l8bw4almnI1' + \ - 'TB7DBnzNsch8ctU4btlgBpfJ2jbrvXZTIl8jXIcykO4crUrQ' +JWT_TOKEN = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NiJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTY0MjE2ODkyMCwianRpIjoiNjM0NGFiNjEtMTIzZC00YWMyLTk3YjMtYmVlYTE2M2JiMWMwIiwidHlwZSI6ImFjY2VzcyIsInN1YiI6InVzZXIxIiwibmJmIjoxNjQyMTY4OTIwLCJyZWFkIjpbInN1bmV0LnNlIl0sIndyaXRlIjpbInN1bmV0LnNlIl19._bX9EHI9h0Vjw75UvYvypqaH3AmsgaATFSUSOT-cYLZHrfMlxios3emr7cyKw-OV_BN5h_XNyrMBV1gIoqAk3A' JWT_HEADER = {'Authorization': f'Bearer {JWT_TOKEN}'} diff --git a/tools/jwt_producer.py b/tools/jwt_producer.py index ea033a6..a024c13 100644 --- a/tools/jwt_producer.py +++ b/tools/jwt_producer.py @@ -7,17 +7,30 @@ import jwt def usage(): progname = sys.argv[0] - print(f'{progname} -p <path to private key> ' + - '-d <domain, for example sunet.se> ', - '-t <type, can be access or scanner>') + print(f'Usage: {progname} [-p <path>] [-w <value>] [-r <value>]\n' + + ' -p <path to private key>\n' + + ' -w <write, comma separated list of domains>\n' + + ' -r <read, comma separated list of domains>\n' + + ' -e <print export statement') sys.exit(0) -def create_token(private_key, token_type, domain): +def create_token(private_key, write_domains, read_domains): + write_claim = list() + read_claim = list() + + if write_domains: + write_claim = write_domains.split(',') + + if read_domains: + read_claim = read_domains.split(',') + payload = { + 'sub': 'test', + 'fresh': False, 'type': 'access', - 'domains': [domain], # We'll just do one domain now - 'user': token_type + 'write': write_claim, + 'read': read_claim } with open(private_key, "r") as fd: @@ -27,27 +40,40 @@ def create_token(private_key, token_type, domain): if __name__ == '__main__': + read_domains = None + write_domains = None + private_key = None + export = False + try: - opts, args = getopt.getopt(sys.argv[1:], 'p:d:t:') + opts, args = getopt.getopt(sys.argv[1:], 'p:w:r:eh') except getopt.GetoptError: usage() - if len(sys.argv) != 7: - usage() - for opt, arg in opts: if opt == '-p': private_key = arg - elif opt == '-d': - domain = arg - elif opt == '-t': - token_type = arg - - if token_type != "access" and token_type != "scanner": - usage() + elif opt == '-w': + write_domains = arg + elif opt == '-r': + read_domains = arg + elif opt == '-e': + export = True + elif opt == '-h': + usage() else: usage() - token = create_token(private_key, token_type, domain).decode('utf-8') + if not private_key: + usage() + + if not write_domains and not read_domains: + usage() + + token = create_token(private_key, write_domains, + read_domains) - print(f'{token}') + if export: + print(f'export JWT_TOKEN={token}') + else: + print(f'{token}') |