You've already forked oncall
mirror of
https://github.com/linkedin/oncall.git
synced 2025-11-26 23:10:47 +02:00
add api endpoints to invalidate ical keys (#302)
* add api endpoints to invalidate ical keys * invalidate ical_key during user-sync process
This commit is contained in:
@@ -102,9 +102,12 @@ def init(application, config):
|
||||
application.add_route('/api/v0/users/{user_name}/ical', user_ical)
|
||||
application.add_route('/api/v0/teams/{team}/ical', team_ical)
|
||||
|
||||
from . import ical_key_user, ical_key_team
|
||||
from . import ical_key_user, ical_key_team, ical_key_detail, ical_key_requester
|
||||
application.add_route('/api/v0/ical_key/user/{user_name}', ical_key_user)
|
||||
application.add_route('/api/v0/ical_key/team/{team}', ical_key_team)
|
||||
# available to admin only
|
||||
application.add_route('/api/v0/ical_key/key/{key}', ical_key_detail)
|
||||
application.add_route('/api/v0/ical_key/requester/{requester}', ical_key_requester)
|
||||
|
||||
from . import public_ical
|
||||
application.add_route('/api/v0/ical/{key}', public_ical)
|
||||
|
||||
@@ -15,7 +15,7 @@ def get_name_and_type_from_key(key):
|
||||
FROM `ical_key`
|
||||
WHERE `key` = %s
|
||||
''',
|
||||
(key))
|
||||
(key, ))
|
||||
if cursor.rowcount != 0:
|
||||
row = cursor.fetchone()
|
||||
result = (row[0], row[1])
|
||||
@@ -83,3 +83,79 @@ def delete_ical_key(requester, name, type):
|
||||
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
|
||||
#####
|
||||
# admin actions below
|
||||
#####
|
||||
|
||||
|
||||
def get_ical_key_detail(key):
|
||||
connection = db.connect()
|
||||
cursor = connection.cursor(db.DictCursor)
|
||||
|
||||
cursor.execute(
|
||||
'''
|
||||
SELECT `requester`, `name`, `type`, `time_created`
|
||||
FROM `ical_key`
|
||||
WHERE `key` = %s
|
||||
''',
|
||||
(key, ))
|
||||
# fetchall because we may want to know if there is any key (uuid) collision
|
||||
results = cursor.fetchall()
|
||||
|
||||
cursor.close()
|
||||
connection.close()
|
||||
return results
|
||||
|
||||
|
||||
def get_ical_key_detail_by_requester(requester):
|
||||
connection = db.connect()
|
||||
cursor = connection.cursor(db.DictCursor)
|
||||
|
||||
cursor.execute(
|
||||
'''
|
||||
SELECT `key`, `name`, `type`, `time_created`
|
||||
FROM `ical_key`
|
||||
WHERE `requester` = %s
|
||||
''',
|
||||
(requester, ))
|
||||
results = cursor.fetchall()
|
||||
|
||||
cursor.close()
|
||||
connection.close()
|
||||
return results
|
||||
|
||||
|
||||
def invalidate_ical_key(key):
|
||||
connection = db.connect()
|
||||
cursor = connection.cursor()
|
||||
|
||||
cursor.execute(
|
||||
'''
|
||||
DELETE FROM `ical_key`
|
||||
WHERE
|
||||
`key` = %s
|
||||
''',
|
||||
(key, ))
|
||||
connection.commit()
|
||||
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
|
||||
def invalidate_ical_key_by_requester(requester):
|
||||
connection = db.connect()
|
||||
cursor = connection.cursor()
|
||||
|
||||
cursor.execute(
|
||||
'''
|
||||
DELETE FROM `ical_key`
|
||||
WHERE
|
||||
`requester` = %s
|
||||
''',
|
||||
(requester, ))
|
||||
connection.commit()
|
||||
|
||||
cursor.close()
|
||||
connection.close()
|
||||
|
||||
37
src/oncall/api/v0/ical_key_detail.py
Normal file
37
src/oncall/api/v0/ical_key_detail.py
Normal file
@@ -0,0 +1,37 @@
|
||||
# Copyright (c) LinkedIn Corporation. All rights reserved. Licensed under the BSD-2 Clause license.
|
||||
# See LICENSE in the project root for license information.
|
||||
|
||||
from falcon import HTTPNotFound, HTTPForbidden
|
||||
from ujson import dumps as json_dumps
|
||||
|
||||
from ...auth import login_required, check_ical_key_admin
|
||||
from .ical_key import get_ical_key_detail, invalidate_ical_key
|
||||
|
||||
|
||||
@login_required
|
||||
def on_get(req, resp, key):
|
||||
challenger = req.context['user']
|
||||
if not check_ical_key_admin(challenger):
|
||||
raise HTTPForbidden(
|
||||
'Unauthorized',
|
||||
'Action not allowed: "%s" is not an admin of ical_key' % (challenger, ),
|
||||
)
|
||||
|
||||
results = get_ical_key_detail(key)
|
||||
if not results:
|
||||
raise HTTPNotFound()
|
||||
|
||||
resp.body = json_dumps(results)
|
||||
resp.set_header('Content-Type', 'application/json')
|
||||
|
||||
|
||||
@login_required
|
||||
def on_delete(req, resp, key):
|
||||
challenger = req.context['user']
|
||||
if not check_ical_key_admin(challenger):
|
||||
raise HTTPForbidden(
|
||||
'Unauthorized',
|
||||
'Action not allowed: "%s" is not an admin of ical_key' % (challenger, ),
|
||||
)
|
||||
|
||||
invalidate_ical_key(key)
|
||||
40
src/oncall/api/v0/ical_key_requester.py
Normal file
40
src/oncall/api/v0/ical_key_requester.py
Normal file
@@ -0,0 +1,40 @@
|
||||
# Copyright (c) LinkedIn Corporation. All rights reserved. Licensed under the BSD-2 Clause license.
|
||||
# See LICENSE in the project root for license information.
|
||||
|
||||
from falcon import HTTPNotFound, HTTPForbidden
|
||||
from ujson import dumps as json_dumps
|
||||
|
||||
from ...auth import login_required, check_ical_key_admin
|
||||
from .ical_key import (
|
||||
get_ical_key_detail_by_requester,
|
||||
invalidate_ical_key_by_requester,
|
||||
)
|
||||
|
||||
|
||||
@login_required
|
||||
def on_get(req, resp, requester):
|
||||
challenger = req.context['user']
|
||||
if not check_ical_key_admin(challenger):
|
||||
raise HTTPForbidden(
|
||||
'Unauthorized',
|
||||
'Action not allowed: "%s" is not an admin of ical_key' % (challenger, ),
|
||||
)
|
||||
|
||||
results = get_ical_key_detail_by_requester(requester)
|
||||
if not results:
|
||||
raise HTTPNotFound()
|
||||
|
||||
resp.body = json_dumps(results)
|
||||
resp.set_header('Content-Type', 'application/json')
|
||||
|
||||
|
||||
@login_required
|
||||
def on_delete(req, resp, requester):
|
||||
challenger = req.context['user']
|
||||
if not check_ical_key_admin(challenger):
|
||||
raise HTTPForbidden(
|
||||
'Unauthorized',
|
||||
'Action not allowed: "%s" is not an admin of ical_key' % (challenger, ),
|
||||
)
|
||||
|
||||
invalidate_ical_key_by_requester(requester)
|
||||
@@ -32,6 +32,10 @@ def is_god(challenger):
|
||||
return is_god != 0
|
||||
|
||||
|
||||
def check_ical_key_admin(challenger):
|
||||
return is_god(challenger)
|
||||
|
||||
|
||||
def check_user_auth(user, req):
|
||||
"""
|
||||
Check to see if current user is user or admin of team where user is in
|
||||
|
||||
@@ -88,6 +88,13 @@ def prune_user(engine, username):
|
||||
logger.error('Deleting user %s failed: %s', username, e)
|
||||
stats['sql_errors'] += 1
|
||||
|
||||
try:
|
||||
engine.execute('DELETE FROM `ical_key` WHERE `requester` = %s', username)
|
||||
logger.info('Invalidated ical_key of inactive user %s', username)
|
||||
except Exception as e:
|
||||
logger.error('Invalidating ical_key of inactive user %s failed: %s', username, e)
|
||||
stats['sql_errors'] += 1
|
||||
|
||||
|
||||
def fetch_ldap():
|
||||
ldap.set_option(ldap.OPT_X_TLS_REQUIRE_CERT, ldap.OPT_X_TLS_ALLOW)
|
||||
|
||||
Reference in New Issue
Block a user