diff --git a/hammer/identification/lambdas/api/authorizer.py b/hammer/identification/lambdas/api/authorizer.py index 79f3262e..94ddb538 100644 --- a/hammer/identification/lambdas/api/authorizer.py +++ b/hammer/identification/lambdas/api/authorizer.py @@ -15,7 +15,7 @@ def lambda_handler(event, context): #logging.debug("Client token: " + event['authorizationToken']) logging.debug("Method ARN: " + event['methodArn']) - if event['authorizationToken'] != config.api.token: + if event['authorizationToken'] not in config.api.tokens: raise Exception('Unauthorized') principalId = 'hammer-api-user' diff --git a/hammer/identification/lambdas/api/entrypoint.py b/hammer/identification/lambdas/api/entrypoint.py index a4c0e163..6c08c85f 100644 --- a/hammer/identification/lambdas/api/entrypoint.py +++ b/hammer/identification/lambdas/api/entrypoint.py @@ -183,6 +183,13 @@ def lambda_handler(event, context): tags = payload.get("tags", None) ids = payload.get("ids", None) + config = Config() + auth_token = event['headers']['auth'] + accounts = config.api.tokens[auth_token]['accounts'] + if accounts: + if account_id not in accounts: + return bad_request(text='You do not have access to specified account.') + action = event.get("path", "")[1:] method = event.get("httpMethod") # do not forget to allow path in authorizer.py while extending this list diff --git a/hammer/identification/lambdas/api/responses.py b/hammer/identification/lambdas/api/responses.py index 2c126dfe..f39e56f2 100644 --- a/hammer/identification/lambdas/api/responses.py +++ b/hammer/identification/lambdas/api/responses.py @@ -4,8 +4,14 @@ def error_response(code, text): response['body'] = text return response + def server_error(text=""): return error_response(500, text) + def bad_request(text=""): return error_response(400, text) + + +def unauthorized(text=""): + return error_response(401, text) diff --git a/hammer/library/config.py b/hammer/library/config.py index 504f1a1d..8bc38ab1 100755 --- a/hammer/library/config.py +++ b/hammer/library/config.py @@ -288,8 +288,8 @@ def __init__(self, config): self._config = config @property - def token(self): - return self._config.get("credentials", {}).get("token", None) + def tokens(self): + return self._config.get("credentials", {}).get("tokens", None) @property def url(self): diff --git a/hammer/tools/add_user.py b/hammer/tools/add_user.py new file mode 100644 index 00000000..f9cd4afd --- /dev/null +++ b/hammer/tools/add_user.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python3.6 + +import boto3 +import argparse +import secrets + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Fill ddb credentials') + parser.add_argument("table", help="credentials DDB table name") + parser.add_argument("username", type=str, help='API user name') + parser.add_argument("--token", type=str, dest='token', default='', + help='Token that is used to authenticate API requests') + parser.add_argument("--accounts", type=str, dest='accounts', + help="Accounts that is accessible for scan for this user. Please use comma as a separator. " + "By default, all accounts are accessible") + + args = parser.parse_args() + + dynamodb = boto3.resource('dynamodb') + table = dynamodb.Table(args.table) + + api_creds = table.get_item(Key={'service': 'api'})['Item'] + if not api_creds: + api_creds = {'service': 'api', 'credentials': {'tokens': {}}} + if 'tokens' in api_creds['credentials']: + tokens = api_creds['credentials']['tokens'] + else: + api_creds['credentials']['tokens'] = {} + tokens = api_creds['credentials']['tokens'] + token = args.token + if not token: + token = secrets.token_hex() + current_token = None + for k in tokens: + if tokens[k]['username'] == args.username: + current_token = k + if current_token: + tokens.pop(current_token) + + if not args.accounts: + accounts = [] + else: + accounts = args.accounts.split(',') + tokens[token] = {} + tokens[token]['accounts'] = {args.accounts} + tokens[token]['username'] = args.username + + table.put_item(Item=api_creds) + print('Successfully added new user to DDB') diff --git a/hammer/tools/ddb_inject_credentials.py b/hammer/tools/ddb_inject_credentials.py index 0d91a85c..e7d101ed 100755 --- a/hammer/tools/ddb_inject_credentials.py +++ b/hammer/tools/ddb_inject_credentials.py @@ -11,12 +11,6 @@ parser.add_argument("--table", dest="table", default=None, help="credentials DDB table name") - parser.add_argument("--hammer-api-token", - dest="hammer_api_token", nargs='?', const=-1, type=str, - help="Hammer API token") - parser.add_argument("--hammer-api-url", - dest="hammer_api_url", nargs='?', const=-1, type=str, - help="Hammer API url") parser.add_argument("--slack-api-token", dest="slack_api_token", default=None, help="Slack API token") @@ -32,6 +26,9 @@ parser.add_argument("--jira-access-token-secret", dest="jira_access_token_secret", default=None, help="JIRA access token_secret") + parser.add_argument("--hammer-api-url", + dest="hammer_api_url", nargs='?', const=-1, type=str, + help="Hammer API url") args = parser.parse_args() @@ -58,11 +55,8 @@ } } - if args.hammer_api_token != None: - # generate new secret if secret value is not set - creds["api"] = {"token": secrets.token_hex() if args.hammer_api_token == -1 else args.hammer_api_token} - - if args.hammer_api_url != None: + if args.hammer_api_url is not None: + creds['api'] = {} creds["api"]["url"] = args.hammer_api_url if not creds: