def delete_perm(perm_id): perm = Permission.find_by_id(perm_id) if not perm: raise ApiError('not found', 404) admin_audit_trail.send(current_app._get_current_object(), event='permission-deleted', message='', user=g.user, customers=g.customers, scopes=g.scopes, resource_id=perm.id, type='permission', request=request) if perm.delete(): return jsonify(status='ok') else: raise ApiError('failed to delete permission', 500)
def delete_group(group_id): group = Group.find_by_id(group_id) if not group: raise ApiError('not found', 404) admin_audit_trail.send(current_app._get_current_object(), event='group-deleted', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=group.id, type='group', request=request) if group.delete(): return jsonify(status='ok') else: raise ApiError('failed to delete user group', 500)
def delete_key(key): key = ApiKey.find_by_id(key) if not key: raise ApiError('not found', 404) admin_audit_trail.send(current_app._get_current_object(), event='apikey-deleted', message='', user=g.user, customers=g.customers, scopes=g.scopes, resource_id=key.id, type='apikey', request=request) if key.delete(): return jsonify(status='ok') else: raise ApiError('failed to delete API key', 500)
def delete_user(user_id): user = User.find_by_id(user_id) if not user: raise ApiError('not found', 404) admin_audit_trail.send(current_app._get_current_object(), event='user-deleted', message='', user=g.user, customers=g.customers, scopes=g.scopes, resource_id=user.id, type='user', request=request) if user.delete(): return jsonify(status='ok') else: raise ApiError('failed to delete user', 500)
def __init__(self, page: int = 1, page_size: int = None, items: int = 0) -> None: self.page = page self.page_size = page_size or current_app.config['DEFAULT_PAGE_SIZE'] self.items = items if items and self.page > self.pages or self.page < 1: raise ApiError('page out of range: 1-%s' % self.pages, 416)
def update_perm(perm_id): if not request.json: raise ApiError('nothing to change', 400) for s in request.json.get('scopes', []): if s not in list(Scope): raise ApiError("'{}' is not a valid Scope".format(s), 400) perm = Permission.find_by_id(perm_id) if not perm: raise ApiError('not found', 404) admin_audit_trail.send(current_app._get_current_object(), event='permission-updated', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=perm.id, type='permission', request=request) if perm.update(**request.json): return jsonify(status='ok') else: raise ApiError('failed to update permission', 500)
def create_heartbeat(): try: heartbeat = Heartbeat.parse(request.json) except ValueError as e: raise ApiError(str(e), 400) if g.get('customer', None): heartbeat.customer = g.get('customer') try: heartbeat = heartbeat.create() except Exception as e: raise ApiError(str(e), 500) if heartbeat: return jsonify(status="ok", id=heartbeat.id, heartbeat=heartbeat.serialize), 201 else: raise ApiError("insert or update of received heartbeat failed", 500)
def create_heartbeat(): try: heartbeat = Heartbeat.parse(request.json) except ValueError as e: raise ApiError(str(e), 400) heartbeat.customer = assign_customer(wanted=heartbeat.customer, permission='admin:heartbeats') try: heartbeat = heartbeat.create() except Exception as e: raise ApiError(str(e), 500) if heartbeat: return jsonify(status="ok", id=heartbeat.id, heartbeat=heartbeat.serialize), 201 else: raise ApiError("insert or update of received heartbeat failed", 500)
def keycloak(): if not current_app.config['KEYCLOAK_URL']: return jsonify( status="error", message="Must define KEYCLOAK_URL setting in server configuration." ), 503 access_token_url = "{0}/auth/realms/{1}/protocol/openid-connect/token".format( current_app.config['KEYCLOAK_URL'], current_app.config['KEYCLOAK_REALM']) payload = { 'client_id': request.json['clientId'], 'client_secret': current_app.config['OAUTH2_CLIENT_SECRET'], 'redirect_uri': request.json['redirectUri'], 'grant_type': 'authorization_code', 'code': request.json['code'], } try: r = requests.post(access_token_url, data=payload) except Exception: return jsonify(status="error", message="Failed to call Keycloak API over HTTPS") access_token = r.json() headers = { "Authorization": "{0} {1}".format(access_token['token_type'], access_token['access_token']) } r = requests.get( "{0}/auth/realms/{1}/protocol/openid-connect/userinfo".format( current_app.config['KEYCLOAK_URL'], current_app.config['KEYCLOAK_REALM']), headers=headers) profile = r.json() roles = profile['roles'] login = profile['preferred_username'] if is_authorized('ALLOWED_KEYCLOAK_ROLES', roles): raise ApiError("User %s is not authorized" % login, 403) customers = get_customers(login, groups=roles) token = create_token(profile['sub'], profile['name'], login, provider='keycloak', customers=customers, roles=roles) return jsonify(token=token.tokenize)
def delete_blackout(blackout_id): customer = g.get('customer', None) blackout = Blackout.find_by_id(blackout_id, customer) if not blackout: raise ApiError('not found', 404) write_audit_trail.send(current_app._get_current_object(), event='blackout-deleted', message='', user=g.user, customers=g.customers, scopes=g.scopes, resource_id=blackout.id, type='blackout', request=request) if blackout.delete(): return jsonify(status='ok') else: raise ApiError('failed to delete blackout', 500)
def get_group_users(group_id): if not Group.find_by_id(group_id): raise ApiError('not found', 404) group_users = GroupUsers.find_by_id(group_id) if group_users: return jsonify(status='ok', users=[user.serialize for user in group_users], total=len(group_users)) else: return jsonify(status='ok', users=[], total=0)
def delete_heartbeat(heartbeat_id): customer = g.get('customer', None) heartbeat = Heartbeat.find_by_id(heartbeat_id, customer) if not heartbeat: raise ApiError('not found', 404) write_audit_trail.send(current_app._get_current_object(), event='heartbeat-deleted', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=heartbeat.id, type='heartbeat', request=request) if heartbeat.delete(): return jsonify(status='ok') else: raise ApiError('failed to delete heartbeat', 500)
def incoming(self, query_string, payload): # logging.info("get alert: %s", payload['alerts']) # transform this alert group to related each other related_alert = [] for alert in payload['alerts']: related_alert.append(alert['labels']['event']) #logging.info(related_alert) if payload and 'alerts' in payload: external_url = payload.get('externalURL') try: return [ parse_alertmanager(alert, external_url, related_alert) for alert in payload['alerts'] ] except Exception as e: logging.error(e) raise ApiError('Error : ' + e, 400) else: raise ApiError('no alerts in Alertmanager notification payload', 400)
def gitlab(): access_token_url = current_app.config['GITLAB_URL'] + '/oauth/token' tokeninfo_url = current_app.config['GITLAB_URL'] + '/oauth/token/info' userinfo_url = current_app.config['GITLAB_URL'] + '/oauth/userinfo' gitlab_api_url = current_app.config['GITLAB_URL'] + '/api/v4' payload = { 'client_id': request.json['clientId'], 'client_secret': current_app.config['OAUTH2_CLIENT_SECRET'], 'redirect_uri': request.json['redirectUri'], 'grant_type': 'authorization_code', 'code': request.json['code'], } try: r = requests.post(access_token_url, data=payload) except Exception: return jsonify(status="error", message="Failed to call Gitlab API over HTTPS") token = r.json() headers = {'Authorization': 'Bearer ' + token['access_token']} r = requests.get(tokeninfo_url, headers=headers) scopes = r.json().get('scopes', []) current_app.logger.info('GitLab scopes: {}'.format(scopes)) if 'openid' in scopes: r = requests.post(userinfo_url, headers=headers) profile = r.json() user_id = profile['sub'] login = profile['nickname'] groups = profile.get('groups', []) email_verified = profile.get('email_verified', False) else: r = requests.get(gitlab_api_url + '/user', headers=headers) profile = r.json() user_id = profile['id'] login = profile['username'] r = requests.get(gitlab_api_url + '/groups', headers=headers) groups = [g['path'] for g in r.json()] email_verified = True if profile.get('email', None) else False if not_authorized('ALLOWED_GITLAB_GROUPS', groups): raise ApiError("User %s is not authorized" % login, 403) customers = get_customers(login, groups) token = create_token(user_id, profile.get('name', '@'+login), login, provider='gitlab', customers=customers, groups=groups, email=profile.get('email', None), email_verified=email_verified) return jsonify(token=token.tokenize)
def add_note(alert_id): note_text = request.json.get('text') or request.json.get('note') if not note_text: raise ApiError("must supply 'note' text") customers = g.get('customers', None) alert = Alert.find_by_id(alert_id, customers) if not alert: raise ApiError('not found', 404) note = alert.add_note(note_text) write_audit_trail.send(current_app._get_current_object(), event='alert-note-added', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=note.id, type='note', request=request) if note: return jsonify(status='ok', id=note.id, note=note.serialize), 201, {'Location': absolute_url('/alert/{}/note/{}'.format(alert.id, note.id))} else: raise ApiError('failed to add note for alert', 500)
def pingdom(): try: incomingAlert = parse_pingdom(request.json) except ValueError as e: raise ApiError(str(e), 400) incomingAlert.customer = assign_customer(wanted=incomingAlert.customer) add_remote_ip(request, incomingAlert) try: alert = process_alert(incomingAlert) except RejectException as e: raise ApiError(str(e), 403) except Exception as e: raise ApiError(str(e), 500) if alert: return jsonify(status='ok', id=alert.id, alert=alert.serialize), 201 else: raise ApiError('insert or update of pingdom check failed', 500)
def delete_alert(alert_id): customers = g.get('customers', None) alert = Alert.find_by_id(alert_id, customers) if not alert: raise ApiError('not found', 404) write_audit_trail.send(current_app._get_current_object(), event='alert-deleted', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=alert.id, type='alert', request=request) if alert.delete(): return jsonify(status='ok') else: raise ApiError('failed to delete alert', 500)
def newrelic(): try: incomingAlert = parse_newrelic(request.json) except ValueError as e: raise ApiError(str(e), 400) incomingAlert.customer = assign_customer(wanted=incomingAlert.customer) add_remote_ip(request, incomingAlert) try: alert = process_alert(incomingAlert) except RejectException as e: raise ApiError(str(e), 403) except Exception as e: raise ApiError(str(e), 500) if alert: return jsonify(status="ok", id=alert.id, alert=alert.serialize), 201 else: raise ApiError("insert or update of New Relic alert failed", 500)
def cloudwatch(): try: incomingAlert = parse_notification(request.get_json(force=True)) except ValueError as e: raise ApiError(str(e), 400) incomingAlert.customer = assign_customer(wanted=incomingAlert.customer) add_remote_ip(request, incomingAlert) try: alert = process_alert(incomingAlert) except RejectException as e: raise ApiError(str(e), 403) except Exception as e: raise ApiError(str(e), 500) if alert: return jsonify(status='ok', id=alert.id, alert=alert.serialize), 201 else: raise ApiError('insert or update of cloudwatch alarm failed', 500)
def create_perm(): try: perm = Permission.parse(request.json) except ValueError as e: raise ApiError(str(e), 400) for want_scope in perm.scopes: if not Permission.is_in_scope(want_scope, g.scopes): raise ApiError( "Requested scope '{}' not in existing scopes: {}".format( want_scope, ','.join(g.scopes)), 403) try: perm = perm.create() except Exception as e: raise ApiError(str(e), 500) if perm: return jsonify(status='ok', id=perm.id, permission=perm.serialize), 201 else: raise ApiError('create API key failed', 500)
def action_alert(alert_id): action = request.json.get('action', None) text = request.json.get('text', '%s operator action' % action) timeout = request.json.get('timeout', None) if not action: raise ApiError("must supply 'action' as json data", 400) customers = g.get('customers', None) alert = Alert.find_by_id(alert_id, customers) if not alert: raise ApiError('not found', 404) try: alert, action, text, timeout = process_action(alert, action, text, timeout) alert = alert.from_action(action, text, timeout) except RejectException as e: write_audit_trail.send(current_app._get_current_object(), event='alert-action-rejected', message=alert.text, user=g.login, customers=g.customers, scopes=g.scopes, resource_id=alert.id, type='alert', request=request) raise ApiError(str(e), 400) except InvalidAction as e: raise ApiError(str(e), 409) except Exception as e: raise ApiError(str(e), 500) write_audit_trail.send(current_app._get_current_object(), event='alert-actioned', message=text, user=g.login, customers=g.customers, scopes=g.scopes, resource_id=alert.id, type='alert', request=request) if alert: return jsonify(status='ok') else: raise ApiError('failed to action alert', 500)
def add_note(alert_id): note_text = request.json.get('text') or request.json.get('note') if not note_text: raise ApiError("must supply 'note' text", 400) customers = g.get('customers', None) alert = Alert.find_by_id(alert_id, customers) if not alert: raise ApiError('not found', 404) try: alert, note_text = process_note(alert, note_text) note = alert.add_note(note_text) except RejectException as e: write_audit_trail.send(current_app._get_current_object(), event='alert-note-rejected', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=note.id, type='note', request=request) raise ApiError(str(e), 400) except ForwardingLoop as e: return jsonify(status='ok', message=str(e)), 202 except AlertaException as e: raise ApiError(e.message, code=e.code, errors=e.errors) except Exception as e: raise ApiError(str(e), 500) write_audit_trail.send(current_app._get_current_object(), event='alert-note-added', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=note.id, type='note', request=request) if note: return jsonify(status='ok', id=note.id, note=note.serialize), 201, {'Location': absolute_url('/alert/{}/note/{}'.format(alert.id, note.id))} else: raise ApiError('failed to add note for alert', 500)
def pagerduty(): data = request.json updated = False if data and 'messages' in data: for message in data['messages']: try: incident_key, status, text = parse_pagerduty(message) except ValueError as e: raise ApiError(str(e), 400) customer = g.get('customer', None) try: alert = Alert.get(id=incident_key, customer=customer) except Exception as e: raise ApiError(str(e), 500) if not alert: raise ApiError("not found", 404) try: updated = alert.set_status(status, text) except Exception as e: raise ApiError(str(e), 500) else: raise ApiError("no messages in PagerDuty data payload", 400) if updated: return jsonify(status="ok"), 200 else: raise ApiError("update PagerDuty incident status failed", 500)
def set_status(alert_id): status = request.json.get('status', None) text = request.json.get('text', '') timeout = request.json.get('timeout', None) if not status: raise ApiError("must supply 'status' as json data", 400) customers = g.get('customers', None) alert = Alert.find_by_id(alert_id, customers) if not alert: raise ApiError('not found', 404) try: alert, status, text = process_status(alert, status, text) alert = alert.from_status(status, text, timeout) except RejectException as e: write_audit_trail.send(current_app._get_current_object(), event='alert-status-rejected', message=alert.text, user=g.login, customers=g.customers, scopes=g.scopes, resource_id=alert.id, type='alert', request=request) raise ApiError(str(e), 400) except AlertaException as e: raise ApiError(e.message, code=e.code, errors=e.errors) except Exception as e: raise ApiError(str(e), 500) write_audit_trail.send(current_app._get_current_object(), event='alert-status-changed', message=text, user=g.login, customers=g.customers, scopes=g.scopes, resource_id=alert.id, type='alert', request=request) if alert: return jsonify(status='ok') else: raise ApiError('failed to set status', 500)
def receive(): try: alert = Alert.parse(request.json) except ValueError as e: raise ApiError(str(e), 400) alert.customer = assign_customer(wanted=alert.customer) def audit_trail_alert(event: str): write_audit_trail.send(current_app._get_current_object(), event=event, message=alert.text, user=g.login, customers=g.customers, scopes=g.scopes, resource_id=alert.id, type='alert', request=request) try: alert = process_alert(alert) except RejectException as e: audit_trail_alert(event='alert-rejected') raise ApiError(str(e), 403) except RateLimit as e: audit_trail_alert(event='alert-rate-limited') return jsonify(status='error', message=str(e), id=alert.id), 429 except HeartbeatReceived as heartbeat: audit_trail_alert(event='alert-heartbeat') return jsonify(status='ok', message=str(heartbeat), id=heartbeat.id), 202 except BlackoutPeriod as e: audit_trail_alert(event='alert-blackout') return jsonify(status='ok', message=str(e), id=alert.id), 202 except ForwardingLoop as e: return jsonify(status='ok', message=str(e)), 202 except AlertaException as e: raise ApiError(e.message, code=e.code, errors=e.errors) except Exception as e: raise ApiError(str(e), 500) write_audit_trail.send(current_app._get_current_object(), event='alert-received', message=alert.text, user=g.login, customers=g.customers, scopes=g.scopes, resource_id=alert.id, type='alert', request=request) if alert: return jsonify(status='ok', id=alert.id, alert=alert.serialize), 201 else: raise ApiError('insert or update of received alert failed', 500)
def update_me(): if not request.json: raise ApiError('nothing to change', 400) if 'roles' in request.json: raise ApiError('not allowed to update roles', 400) if 'email_verified' in request.json: raise ApiError('not allowed to set email verified', 400) user = User.find_by_id(g.user_id) if not user: raise ApiError('not found', 404) if 'email' in request.json: user_by_email = User.find_by_email(email=request.json['email']) if user_by_email and user_by_email.id != user.id: raise ApiError('user with that email already exists', 409) updated = user.update(**request.json) write_audit_trail.send(current_app._get_current_object(), event='user-me-updated', message='', user=g.login, customers=g.customers, scopes=g.scopes, resource_id=user.id, type='user', request=request) if updated: return jsonify(status='ok', user=updated.serialize) else: raise ApiError('failed to update user', 500)
def only_json(): # SAML2 Assertion Consumer Service expects POST request with 'Content-Type': 'application/x-www-form-urlencoded' from IdP if request.method == 'POST' and request.path == '/auth/saml' and request.headers[ 'Content-Type'] == 'application/x-www-form-urlencoded': return if request.path == '/auth/logout': return if request.method in ['POST', 'PUT'] and not request.is_json: raise ApiError( "POST and PUT requests must set 'Content-Type' to 'application/json'", 415)
def verify_email(hash): user = User.verify_hash(hash, salt='confirm') if user: if user.email_verified: raise ApiError('email already verified', 400) user.set_email_verified() auth_audit_trail.send(current_app._get_current_object(), event='basic-auth-verify-email', message='user confirm email address', user=user.email, customers=[], scopes=[], resource_id=user.id, type='user', request=request) return jsonify(status='ok', message='email address {} confirmed'.format(user.email)) else: raise ApiError('invalid confirmation hash', 400)
def create_blackout(): try: blackout = Blackout.parse(request.json) except Exception as e: raise ApiError(str(e), 400) if g.get('customer', None): blackout.customer = g.get('customer') try: blackout = blackout.create() except Exception as e: raise ApiError(str(e), 500) if blackout: return jsonify(status="ok", id=blackout.id, blackout=blackout.serialize), 201, { 'Location': absolute_url('/blackout/' + blackout.id) } else: raise ApiError("insert blackout failed", 500)
def bulk_action_alert(): from alerta.tasks import action_alerts action = request.json.get('action', None) text = request.json.get('text', 'bulk status update') timeout = request.json.get('timeout', None) if not action: raise ApiError("must supply 'action' as json data", 400) query = qb.from_params(request.args) alerts = [alert.id for alert in Alert.find_all(query)] if not alerts: raise ApiError('not found', 404) task = action_alerts.delay(alerts, action, text, timeout) return jsonify(status='ok', message=f'{len(alerts)} alerts queued for action'), 202, { 'Location': absolute_url('/_bulk/task/' + task.id) }