def _credential_init(self): logger.info('Bootstrapping credentials') # credential bootstrap self.global_configuration['system_user_auth'] = (None, None) if self.require_system_user: gotauth = False max_retries = 60 for count in range(1, max_retries): try: with session_scope() as dbsession: mgr = manager_factory.for_session(dbsession) self.global_configuration['system_user_auth'] = mgr.get_system_credentials() if self.global_configuration['system_user_auth'] != (None, None): gotauth = True break else: logger.error('cannot get system user auth credentials yet, retrying (' + str(count) + ' / ' + str(max_retries) + ')') time.sleep(5) except Exception as err: logger.exception('cannot get system-user auth credentials - service may not have system level access') self.global_configuration['system_user_auth'] = (None, None) gotauth = False if not gotauth: raise Exception('service requires system user auth to start') logger.info('Credential initialization complete')
def list_user_credentials(accountname, username): """ GET /accounts/{accountname}/users/{username}/credentials :param username: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) usr = verify_user(username, accountname, mgr) cred = usr["credentials"].get(UserAccessCredentialTypes.password) if cred is None: return [], 200 else: cred = credential_db_to_msg(cred) return [cred], 200 except UserNotFoundError as ex: return make_response_error("User not found", in_httpcode=404), 404 except AccountNotFoundError as ex: return make_response_error("Account not found", in_httpcode=404), 404 except Exception as ex: logger.exception("Api Error") return make_response_error(errmsg=str(ex), in_httpcode=500), 500
def delete_user(accountname, username): """ DELETE /accounts/{accountname}/users/{username} :param accountname: :param username: the user to delete :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) verify_user(username, accountname, mgr) if ApiRequestContextProxy.identity().username == username: return make_response_error( 'Cannot delete credential used for authentication of the request', in_httpcode=400), 400 if mgr.delete_user(username): return None, 204 else: return make_response_error( 'Failed to delete user: {}'.format(username), in_httpcode=500), 500 except (UserNotFoundError, AccountNotFoundError): return make_response_error('User not found', in_httpcode=404), 404 except Exception as e: logger.exception('API Error') return make_response_error( 'Internal error deleting user {}'.format(username), in_httpcode=500), 500
def user_account_upgrades_007_008(): logger.info('Upgrading user accounts for multi-user support') from anchore_engine.db import session_scope, legacy_db_users from anchore_engine.subsys.identities import manager_factory, AccountStates from anchore_engine.configuration.localconfig import SYSTEM_ACCOUNT_NAME, ADMIN_ACCOUNT_NAME with session_scope() as session: mgr = manager_factory.for_session(session) for user in legacy_db_users.get_all(): if user['userId'] == ADMIN_ACCOUNT_NAME: account_type = identities.AccountTypes.admin elif user['userId'] == SYSTEM_ACCOUNT_NAME: account_type = identities.AccountTypes.service else: account_type = identities.AccountTypes.user logger.info('Migrating user: {} to new account with name {}, type {}, is_active {}'.format(user['userId'], user['userId'], account_type, user['active'])) accnt = mgr.create_account(account_name=user['userId'], email=user['email'], account_type=account_type) if not user['active']: mgr.update_account_state(accnt['name'], AccountStates.disabled) logger.info('Creating new user record in new account {} with username {}'.format(user['userId'], user['userId'])) mgr.create_user(account_name=user['userId'], username=user['userId'], password=user['password']) logger.info('Deleting old user record') legacy_db_users.delete(user['userId'], session) logger.info('User account upgrade complete')
def create_user(accountname, user): """ POST /accounts/{accountname}/users :param accountname: :param user: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) verify_account(accountname, mgr) usr = mgr.create_user( account_name=accountname, username=user['username'], creator_name=ApiRequestContextProxy.identity().username, password=user['password']) return user_db_to_msg(usr), 200 except UserAlreadyExistsError as ex: return make_response_error('User already exists', in_httpcode=400), 400 except AccountNotFoundError as ex: return make_response_error('Account not found', in_httpcode=404), 404 except Exception as e: logger.exception('API Error') return make_response_error( 'Internal error deleting account {}'.format(accountname)), 500
def activate_account(accountname): """ POST /accounts/{accountname}/activate idempotently activate an account :param accountname: str account name to activate :return: account json object """ try: with session_scope() as session: mgr = manager_factory.for_session(session) verify_account(accountname, mgr) result = mgr.activate_account(accountname) if result: return account_db_to_status_msg(result), 200 else: return make_response_error('Error updating account state'), 500 except AccountNotFoundError as ex: return make_response_error('Account not found', in_httpcode=404), 404 except Exception as e: logger.exception('API Error') return make_response_error('Error activating account', in_httpcode=500), 500
def list_users(accountname): """ GET /accounts/{accountname}/users :param account: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) verify_account(accountname, mgr) users = mgr.list_users(accountname) if users is None: return make_response_error("No such account", in_httpcode=404), 404 response = list(map(user_db_to_msg, users)) return response, 200 except AccountNotFoundError as ex: return make_response_error("Account not found", in_httpcode=404), 404 except Exception as e: logger.exception("API Error") return make_response_error("Error listing account users", in_httpcode=500), 500
def update_account_state(accountname, desired_state): """ POST /accounts/{accountname}/state Body: {"state": "enabled"|"disabled"} :param accountname: str account name to update :param desired_state: json object for desired state to set :return: account json object """ try: with session_scope() as session: mgr = manager_factory.for_session(session) verify_account(accountname, mgr) result = mgr.update_account_state( accountname, AccountStates(desired_state.get("state"))) if result: return account_db_to_status_msg(result), 200 else: return make_response_error("Error updating account state"), 500 except (InvalidStateError, DisableAdminAccountError) as ex: return make_response_error(str(ex), in_httpcode=400), 400 except AccountNotFoundError as ex: return make_response_error("Account not found", in_httpcode=404), 404 except Exception as e: logger.exception("API Error") return make_response_error("Error updating account state", in_httpcode=500), 500
def create_user_credential(accountname, username, credential): """ POST /accounts/{accountname}/users/{username}/credentials :param accountname: str account id for account account record :param username: str username :param credential: json object of the credential type :return: credential json object """ try: with session_scope() as session: mgr = manager_factory.for_session(session) usr = mgr.get_user(username) if not usr or usr['account_name'] != accountname: return make_response_error('Username not found in account'), 404 # For now, only support passwords via the api if credential['type'] != 'password': return make_response_error('Invalid credential type'), 400 if not credential.get('value'): return make_response_error('Invalid credential value, must be non-null and non-empty'), 400 try: cred_type = UserAccessCredentialTypes(credential['type']) except: return make_response_error(errmsg='Invalid credential type'), 400 cred = mgr.add_user_credential(session, creator_name=ApiRequestContextProxy.user(), username=username, credential_type=cred_type, value=credential['value']) return credential_db_to_msg(cred), 200 except Exception as ex: logger.exception('API Error') return make_response_error(errmsg=str(ex)), 500
def delete_user(accountname, username): """ DELETE /accounts/{accountname}/users/{username} :param accountname: :param username: the user to delete :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) usr = verify_user(username, accountname, mgr) if not can_delete_user(usr): return make_response_error('User not allowed to be deleted due to system constraints', in_httpcode=400), 400 elif ApiRequestContextProxy.identity().username == username: return make_response_error('Cannot delete credential used for authentication of the request', in_httpcode=400), 400 else: if mgr.delete_user(username): # Flush from authz system if necessary, will rollback if this fails, but rely on the db state checks first to gate this authorizer.notify(NotificationTypes.principal_deleted, username) return None, 204 else: return make_response_error('Failed to delete user: {}'.format(username), in_httpcode=500), 500 except (UserNotFoundError, AccountNotFoundError): return make_response_error('User not found', in_httpcode=404), 404 except Exception as e: logger.exception('API Error') return make_response_error('Internal error deleting user {}'.format(username), in_httpcode=500), 500
def delete_user(accountname, username): """ DELETE /accounts/{accountname}/users/{username} :param accountname: :param username: the user to delete :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) if request.authorization.accountname == accountname: return make_response_error('Cannot delete credential used for authentication of the request'), 400 user = mgr.get_user(username) if user['account_name'] != accountname: return make_response_error('username {} not valid for account {}'.format(username, accountname)), 404 if mgr.delete_user(username): return '', 200 else: return make_response_error('Failed to delete credential: {}'.format(accountname)), 500 except Exception as ex: logger.exception('API Error') return make_response_error(errmsg=str(ex)), 500
def list_accounts(state=None): """ GET /accounts :param active: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) if state is not None: try: state = AccountStates(state) except: return ( make_response_error( "Bad Request: state {} not a valid value", in_httpcode=400), 400, ) response = mgr.list_accounts(with_state=state) return list(map(account_db_to_msg, response)), 200 except Exception as ex: logger.exception("API Error") return make_response_error("Error listing accounts", in_httpcode=500), 500
def create_account(account): """ POST /accounts :param account: :return: """ try: if account.get('type') != AccountTypes.user.value: return make_response_error( 'Invalid account type: {}. Only valid value is "user"'.format( account.get('type')), in_httpcode=400), 400 with session_scope() as session: mgr = manager_factory.for_session(session) resp = mgr.create_account( account_name=account['name'], account_type=account.get('type', AccountTypes.user.value), email=account.get('email'), creator=ApiRequestContextProxy.identity().username) return account_db_to_msg(resp), 200 except AccountAlreadyExistsError as ex: return make_response_error(errmsg='Account already exists', in_httpcode=400), 400 except Exception as ex: logger.exception('Unexpected Error creating account') return make_response_error('Error creating account', in_httpcode=500), 500
def delete_user_credential(accountname, username, credential_type): """ DELETE /accounts/{accountname}/users/{username}/credentials?credential_type=password :param username: :param credential_type: :return: """ if not credential_type: return make_response_error('credential type must be specified', in_httpcode=400), 400 try: with session_scope() as session: mgr = manager_factory.for_session(session) usr = verify_user(username, accountname, mgr) if credential_type != 'password': return make_response_error('Invalid credential type', in_httpcode=400), 400 if username == ApiRequestContextProxy.identity().username: return make_response_error( 'Cannot delete credential of authenticated user', in_httpcode=400), 400 resp = mgr.delete_user_credential(username, credential_type) return None, 204 except UserNotFoundError as ex: return make_response_error('User not found', in_httpcode=404), 404 except AccountNotFoundError as ex: return make_response_error('Account not found', in_httpcode=404), 404 except Exception as ex: logger.exception('Api Error') return make_response_error(errmsg=str(ex), in_httpcode=500), 500
def create_user(accountname, user): """ POST /accounts/{accountname}/users :param accountname: :param user: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) verify_account(accountname, mgr) try: usr = mgr.create_user(account_name=accountname, username=user['username'], password=user['password']) except ValueError as ex: return make_response_error('Validation failed: {}'.format(ex), in_httpcode=400), 400 # Flush from authz system if necessary, will rollback if this fails, but rely on the db state checks first to gate this authorizer.notify(NotificationTypes.principal_created, usr['username']) return user_db_to_msg(usr), 200 except UserAlreadyExistsError as ex: return make_response_error('User already exists', in_httpcode=400), 400 except AccountNotFoundError as ex: return make_response_error('Account not found', in_httpcode=404), 404 except Exception as e: logger.exception('API Error') return make_response_error('Internal error adding user'), 500
def create_account(account): """ POST /accounts :param account: :return: """ try: try: can_create_account(account) except ValueError as ex: return make_response_error('Invalid account request: {}'.format( ex.args[0]), in_httpcode=400), 400 except Exception as ex: logger.exception('Unexpected exception in account validation') return make_response_error('Invalid account request', in_httpcode=400), 400 with session_scope() as session: mgr = manager_factory.for_session(session) try: resp = mgr.create_account(account_name=account['name'], account_type=account.get( 'type', AccountTypes.user.value), email=account.get('email')) except ValueError as ex: return make_response_error('Validation failed: {}'.format(ex), in_httpcode=400), 400 authorizer.notify(NotificationTypes.domain_created, account['name']) # Initialize account stuff try: _init_policy(account['name'], config=get_config()) except Exception: logger.exception( 'Could not initialize policy bundle for new account: {}'. format(account['name'])) raise return account_db_to_msg(resp), 200 except AccountAlreadyExistsError as ex: return make_response_error(errmsg='Account already exists', in_httpcode=400), 400 except Exception as ex: logger.exception('Unexpected Error creating account') return make_response_error('Error creating account', in_httpcode=500), 500
def delete_account(accountname): """ DELETE /account/{accountname} :param accountname: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) account = verify_account(accountname, mgr) if not can_delete_account(account): return ( make_response_error("Account cannot be deleted", in_httpcode=400), 400, ) else: account = mgr.update_account_state(accountname, AccountStates.deleting) # Flush from authz system if necessary authorizer.notify(NotificationTypes.domain_deleted, accountname) users = mgr.list_users(accountname) for user in users: # Flush users logger.debug( "Deleting account user {} on authz system if using plugin" .format(user["username"])) authorizer.notify(NotificationTypes.principal_deleted, user["username"]) logger.debug("Deleting account user: {}".format( user["username"])) mgr.delete_user(user["username"]) return account_db_to_status_msg(account), 200 except InvalidStateError as ex: return make_response_error(str(ex), in_httpcode=400), 400 except AccountNotFoundError as ex: return make_response_error("Account not found", in_httpcode=404), 404 except Exception as e: logger.exception("API Error") return make_response_error("Error deleting account", in_httpcode=500), 500
def get_users_account(): """ GET /account :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) account = mgr.get_account(ApiRequestContextProxy.namespace()) return account_db_to_msg(account), 200 except Exception as ex: logger.exception("API Error") return make_response_error(errmsg=str(ex)), 500
def delete_user_credential(accountname, username, credential_type, uuid): """ DELETE /accounts/{accountname}/users/{username}/credentials?uuid :param username: :param credential_type: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) resp = mgr.delete_user_credential(username, credential_type) return resp, 200 except Exception as ex: logger.exception('API Error') return make_response_error(errmsg=str(ex)), 500
def create_user_credential(accountname, username, credential): """ POST /accounts/{accountname}/users/{username}/credentials :param accountname: str account id for account account record :param username: str username :param credential: json object of the credential type :return: credential json object """ try: with session_scope() as session: mgr = manager_factory.for_session(session) user = verify_user(username, accountname, mgr) if user['type'] != UserTypes.native: return make_response_error( "Users with type other than 'native' cannot have password credentials", in_httpcode=400), 400 # For now, only support passwords via the api if credential['type'] != 'password': return make_response_error('Invalid credential type', in_httpcode=404), 404 if not credential.get('value'): return make_response_error( 'Invalid credential value, must be non-null and non-empty', in_httpcode=400), 400 try: cred_type = UserAccessCredentialTypes(credential['type']) except: return make_response_error(errmsg='Invalid credential type', in_httpcode=400), 400 cred = mgr.add_user_credential(username=username, credential_type=cred_type, value=credential['value']) return credential_db_to_msg(cred), 200 except UserNotFoundError as ex: return make_response_error('User not found', in_httpcode=404), 404 except AccountNotFoundError as ex: return make_response_error('Account not found', in_httpcode=404), 404 except Exception as e: logger.exception('API Error') return make_response_error( 'Internal error creating credential {}'.format(accountname)), 500
def create_user(accountname, user): """ POST /accounts/{accountname}/users :param accountname: :param user: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) usr = mgr.create_user(account_name=accountname, username=user['username'], creator_name=ApiRequestContextProxy.user(), password=user['password']) return user_db_to_msg(usr), 200 except Exception as ex: logger.exception('API Error') return make_response_error(errmsg=str(ex)), 500
def get_test_notification(notification_type, request_inputs): """ Build a test notification payload (format should mirror what's returned by get_webhook_schema) :param notification_type: type of notification to send :param request_inputs: metadata from request to test webhook """ with db.session_scope() as dbsession: mgr = manager_factory.for_session(dbsession) notification = notifications.Notification(notification_type, request_inputs['userId'], mgr.get_account(request_inputs['userId'])['email']) logger.debug("Test Notification JSON: {}".format(notification.to_json())) return notification
def get_account(accountname): """ GET /accounts/{accountname} :param accountname: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) account = mgr.get_account(accountname) return account_db_to_msg(account), 200 except Exception as ex: logger.exception('API Error') return make_response_error(errmsg=str(ex)), 500
def internal_client_for(internal_client_cls, userId): """ Return an initialized internal service client for the given userId (namespace) :param cls: :param userId: :param session: :return: """ with session_scope() as session: mgr = manager_factory.for_session(session=session) credential = mgr.get_system_credentials() if credential is None: raise Exception('No cached system credentials found') return internal_client_cls(credential=credential, as_account=userId)
def internal_client_for(internal_client_cls, userId): """ Return an initialized internal service client for the given userId (namespace) :param cls: :param userId: :param session: :return: """ mgr = manager_factory.for_session(session=None) sysuser, syspass = mgr.get_system_credentials() if sysuser is None: raise Exception('No cached system credentials found') return internal_client_cls(user=sysuser, password=syspass, as_account=userId)
def deactivate_account(accountname): """ POST /accounts/{accountname}/deactivate :param accountname: str account Id to deactivate :return: account json object """ try: with session_scope() as session: mgr = manager_factory.for_session(session) result = mgr.deactivate_account(accountname) if result: return account_db_to_status_msg(result), 200 else: return make_response_error('Error updating account state', ), 500 except Exception as ex: logger.exception('API Error') return make_response_error(errmsg=str(ex)), 500
def get_account(accountname): """ GET /accounts/{accountname} :param accountname: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) account = verify_account(accountname, mgr) return account_db_to_msg(account), 200 except AccountNotFoundError as ex: return make_response_error('Account not found', in_httpcode=404), 404 except Exception as ex: logger.exception('API Error') return make_response_error('Error getting account', in_httpcode=500), 500
def delete_account(accountname): """ DELETE /account/{accountname} :param accountname: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) account = verify_account(accountname, mgr) resp = mgr.delete_account(accountname) return None, 204 except AccountNotFoundError as ex: return make_response_error('Account not found', in_httpcode=404), 404 except Exception as e: logger.exception('API Error') return make_response_error('Error deleting account', in_httpcode=500), 500
def delete_account(accountname): """ DELETE /account/{accountname} :param accountname: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) try: resp = mgr.delete_account(accountname) return '', 200 except Exception as e: return make_response_error('Internal error deleting account {}'.format(accountname), ), 500 except Exception as ex: logger.exception('API Error') return make_response_error(errmsg=str(ex)), 500
def list_users(accountname): """ GET /accounts/{accountname}/users :param account: :return: """ try: with session_scope() as session: mgr = manager_factory.for_session(session) users = mgr.list_users(accountname) if users is None: return make_response_error('No such account'), 404 response = list(map(user_db_to_msg, users)) return response, 200 except Exception as ex: logger.exception('API Error') return make_response_error(errmsg=str(ex)), 500