example-apps/internal-knowledge-search/api/app.py (134 lines of code) (raw):
from flask import Flask, jsonify, request, Response, current_app
from flask_cors import CORS
from elasticsearch_client import elasticsearch_client
import os
import sys
import requests
app = Flask(__name__, static_folder="../frontend/build", static_url_path="/")
CORS(app)
def get_identities_index(search_app_name):
search_app = elasticsearch_client.search_application.get(name=search_app_name)
identities_indices = elasticsearch_client.indices.get(index=".search-acl-filter*")
secured_index = [
app_index
for app_index in search_app["indices"]
if ".search-acl-filter-" + app_index in identities_indices
]
if len(secured_index) > 0:
identities_index = ".search-acl-filter-" + secured_index[0]
return identities_index
else:
raise ValueError(
"Could not find identities index for search application %s", search_app_name
)
@app.route("/")
def api_index():
return app.send_static_file("index.html")
@app.route("/api/default_settings", methods=["GET"])
def default_settings():
return {
"elasticsearch_endpoint": os.getenv("ELASTICSEARCH_URL")
or "http://localhost:9200"
}
@app.route("/api/search_proxy/<path:text>", methods=["POST"])
def search(text):
response = requests.request(
method="POST",
url=os.getenv("ELASTICSEARCH_URL") + "/" + text,
data=request.get_data(),
allow_redirects=False,
headers={
"Authorization": request.headers.get("Authorization"),
"Content-Type": "application/json",
},
)
return response.content
@app.route("/api/persona", methods=["GET"])
def personas():
try:
search_app_name = request.args.get("app_name")
identities_index = get_identities_index(search_app_name)
response = elasticsearch_client.search(index=identities_index, size=1000)
hits = response["hits"]["hits"]
personas = [x["_id"] for x in hits]
personas.append("admin")
return personas
except Exception as e:
current_app.logger.warn(
"Encountered error %s while fetching personas, returning default persona", e
)
return ["admin"]
@app.route("/api/indices", methods=["GET"])
def indices():
try:
search_app_name = request.args.get("app_name")
search_app = elasticsearch_client.search_application.get(name=search_app_name)
return search_app["indices"]
except Exception as e:
current_app.logger.warn(
"Encountered error %s while fetching indices, returning no indices", e
)
return []
@app.route("/api/api_key", methods=["GET"])
def api_key():
search_app_name = request.args.get("app_name")
role_name = search_app_name + "-key-role"
default_role_descriptor = {}
default_role_descriptor[role_name] = {
"cluster": [],
"indices": [
{
"names": [search_app_name],
"privileges": ["read"],
"allow_restricted_indices": False,
}
],
"applications": [],
"run_as": [],
"metadata": {},
"transient_metadata": {"enabled": True},
"restriction": {"workflows": ["search_application_query"]},
}
identities_index = get_identities_index(search_app_name)
try:
persona = request.args.get("persona")
if persona == "":
raise ValueError("No persona specified")
role_descriptor = {}
if persona == "admin":
role_descriptor = default_role_descriptor
else:
identity = elasticsearch_client.get(index=identities_index, id=persona)
permissions = identity["_source"]["query"]["template"]["params"][
"access_control"
]
role_descriptor = {
"dls-role": {
"cluster": ["all"],
"indices": [
{
"names": [search_app_name],
"privileges": ["read"],
"query": {
"template": {
"params": {"access_control": permissions},
"source": """{
"bool": {
"should": [
{
"bool": {
"must_not": {
"exists": {
"field": "_allow_access_control"
}
}
}
},
{
"terms": {
"_allow_access_control.enum": {{#toJson}}access_control{{/toJson}}
}
}
]
}
}""",
}
},
}
],
"restriction": {"workflows": ["search_application_query"]},
}
}
api_key = elasticsearch_client.security.create_api_key(
name=search_app_name + "-internal-knowledge-search-example-" + persona,
expiration="1h",
role_descriptors=role_descriptor,
)
return {"api_key": api_key["encoded"]}
except Exception as e:
current_app.logger.warn("Encountered error %s while fetching api key", e)
raise e
if __name__ == "__main__":
app.run(port=3001, debug=True)