@@ -4,14 +4,12 @@ import {updateSettings} from "../store/slices/searchApplicationSettingsSlice";
44import { useToast } from "../contexts/ToastContext" ;
55import { MessageType } from "./Toast" ;
66import { RootState } from "../store/store" ;
7- import { FontAwesomeIcon } from "@fortawesome/react-fontawesome" ;
8- import { faAngleDown , faAngleUp } from "@fortawesome/free-solid-svg-icons" ;
9- import { json } from "react-router-dom" ;
7+
108
119
1210const SearchApplicationSettings : React . FC = ( ) => {
1311 const dispatch = useDispatch ( ) ;
14- const { appName, appUser, appPassword, searchEndpoint, searchPersona} = useSelector ( ( state : RootState ) => state . searchApplicationSettings ) ;
12+ const { appName, appUser, appPassword, searchEndpoint, searchPersona, searchPersonaAPIKey } = useSelector ( ( state : RootState ) => state . searchApplicationSettings ) ;
1513 const { showToast} = useToast ( ) ;
1614
1715 const fetchPersonaOptions = async ( ) => {
@@ -29,12 +27,127 @@ const SearchApplicationSettings: React.FC = () => {
2927 }
3028 }
3129
30+ const roleName = appName + "-key-role"
31+ const defaultRoleDescriptor = {
32+ [ roleName ] : {
33+ "cluster" : [ ] ,
34+ "indices" : [
35+ {
36+ "names" : [
37+ appName
38+ ] ,
39+ "privileges" : [
40+ "read"
41+ ] ,
42+ "allow_restricted_indices" : false
43+ }
44+ ] ,
45+ "applications" : [ ] ,
46+ "run_as" : [ ] ,
47+ "metadata" : { } ,
48+ "transient_metadata" : {
49+ "enabled" : true
50+ } ,
51+ "restriction" : {
52+ "workflows" : [
53+ "search_application_query"
54+ ]
55+ }
56+ }
57+ }
58+ const personaRoleDescriptor = async ( ) => {
59+ const identitiesIndex = ".search-acl-filter-search-sharepoint" //TODO fix hardcoded
60+ const identityPath = searchEndpoint + "/" + identitiesIndex + "/_doc/" + searchPersona
61+ const response = await fetch ( identityPath , { headers : { "Authorization" : "Basic " + btoa ( appUser + ":" + appPassword ) } } ) ;
62+ const jsonData = await response . json ( ) ;
63+ console . log ( "Permissions lookup response is:" )
64+ console . log ( jsonData )
65+ const permissions = jsonData . _source . query . template . params . access_control
66+ return {
67+ "dls-role" : {
68+ "cluster" : [ "all" ] ,
69+ "indices" : [
70+ {
71+ "names" : [ "search-sharepoint" ] , // TODO: hardcoded
72+ "privileges" : [ "read" ] ,
73+ "query" : {
74+ "template" : {
75+ "params" : {
76+ "permissions" : permissions
77+ } ,
78+ 'source' : `
79+ {
80+ "bool": {
81+ "filter": {
82+ "bool": {
83+ "should": [
84+ {
85+ "bool": {
86+ "must_not": {
87+ "exists": {
88+ "field": "_allow_access_control"
89+ }
90+ }
91+ }
92+ },
93+ {
94+ "terms": {
95+ "_allow_access_control": {{#toJson}}permissions{{/toJson}}
96+ }
97+ }
98+ ]
99+ }
100+ }
101+ }
102+ }
103+ `
104+ }
105+ }
106+ }
107+ ] ,
108+ "restriction" : {
109+ "workflows" : [
110+ "search_application_query"
111+ ]
112+ }
113+ }
114+ }
115+ }
116+ const createPersonaAPIKey = async ( persona ) => {
117+ const roleDescriptor = persona == "admin" ? defaultRoleDescriptor : await personaRoleDescriptor ( )
118+ const apiKeyPath = searchEndpoint + "/_security/api_key"
119+ const response = await fetch ( apiKeyPath , {
120+ method : "POST" ,
121+ headers : {
122+ "Authorization" : "Basic " + btoa ( appUser + ":" + appPassword ) ,
123+ "Content-Type" : "application/json" ,
124+ } ,
125+ body : JSON . stringify ( {
126+ "name" : appName + "-internal-knowledge-search-example-" + persona ,
127+ "expiration" : "1h" ,
128+ "role_descriptors" : roleDescriptor ,
129+ "metadata" : {
130+ "application" : appName ,
131+ "createdBy" : appUser
132+ }
133+ } )
134+ } )
135+ const jsonData = await response . json ( )
136+ console . log ( "API key create response is:" )
137+ console . log ( jsonData )
138+ return jsonData . encoded
139+ }
140+
32141 const [ searchPersonaOptions , setSearchPersonaOptions ] = useState ( [ "admin" ] ) ;
33142
34143 useEffect ( ( ) => {
35144 ( async ( ) => {
36- const fetched = await fetchPersonaOptions ( )
37- setSearchPersonaOptions ( fetched )
145+ const fetchedPersonas = await fetchPersonaOptions ( )
146+ setSearchPersonaOptions ( fetchedPersonas )
147+ if ( searchPersonaAPIKey == "missing" ) {
148+ const createdAPIKey = await createPersonaAPIKey ( searchPersona )
149+ updateSearchPersonaAPIKey ( createdAPIKey )
150+ }
38151 } ) ( )
39152 } , [ ] )
40153
@@ -44,24 +157,26 @@ const SearchApplicationSettings: React.FC = () => {
44157 setIsOpen ( ! isOpen ) ;
45158 } ;
46159
47- const handlePersonaChange = ( value : string ) => {
48- updateSearchPersona ( value ) ;
160+ const handlePersonaChange = async ( value : string ) => {
161+ updateSearchPersona ( value , await createPersonaAPIKey ( value ) ) ;
49162 } ;
50163
51164 const handleSave = ( ) => {
52- dispatch ( updateSettings ( { appName, appUser, appPassword, searchEndpoint, searchPersona} ) ) ;
165+ dispatch ( updateSettings ( { appName, appUser, appPassword, searchEndpoint, searchPersona, searchPersonaAPIKey } ) ) ;
53166 showToast ( "Settings saved!" , MessageType . Info ) ;
54167 } ;
55168
56- const updateAppName = ( e ) => dispatch ( updateSettings ( { appName : e . target . value , appUser, appPassword, searchEndpoint, searchPersona} ) )
169+ const updateAppName = ( e ) => dispatch ( updateSettings ( { appName : e . target . value , appUser, appPassword, searchEndpoint, searchPersona, searchPersonaAPIKey} ) )
170+
171+ const updateAppUser = ( e ) => dispatch ( updateSettings ( { appName, appUser : e . target . value , appPassword, searchEndpoint, searchPersona, searchPersonaAPIKey} ) )
57172
58- const updateAppUser = ( e ) => dispatch ( updateSettings ( { appName, appUser : e . target . value , appPassword , searchEndpoint, searchPersona} ) )
173+ const updateAppPassword = ( e ) => dispatch ( updateSettings ( { appName, appUser, appPassword : e . target . value , searchEndpoint, searchPersona, searchPersonaAPIKey } ) )
59174
60- const updateAppPassword = ( e ) => dispatch ( updateSettings ( { appName, appUser, appPassword : e . target . value , searchEndpoint , searchPersona } ) )
175+ const updateSearchEndpoint = ( e ) => dispatch ( updateSettings ( { appName, appUser, appPassword, searchEndpoint : e . target . value , searchPersona , searchPersonaAPIKey } ) )
61176
62- const updateSearchEndpoint = ( e ) => dispatch ( updateSettings ( { appName, appUser, appPassword, searchEndpoint : e . target . value , searchPersona } ) )
177+ const updateSearchPersona = ( persona , apiKey ) => dispatch ( updateSettings ( { appName, appUser, appPassword, searchEndpoint, searchPersona : persona , searchPersonaAPIKey : apiKey } ) )
63178
64- const updateSearchPersona = ( e ) => dispatch ( updateSettings ( { appName, appUser, appPassword, searchEndpoint, searchPersona : e } ) )
179+ const updateSearchPersonaAPIKey = ( apiKey ) => dispatch ( updateSettings ( { appName, appUser, appPassword, searchEndpoint, searchPersona, searchPersonaAPIKey : apiKey } ) )
65180
66181 return (
67182 < div className = "container mx-auto p-4 bg-white rounded shadow-md" >
@@ -154,10 +269,13 @@ const SearchApplicationSettings: React.FC = () => {
154269 < p className = "text-xs mb-2 text-gray-500" > The persona on whose behalf searches will be executed</ p >
155270 < div className = "relative" >
156271 < select
157- onChange = { ( event ) => handlePersonaChange ( event . target . value ) }
272+ onChange = { async ( event ) => await handlePersonaChange ( event . target . value ) }
158273 value = { searchPersona }
159274 className = "flex items-center space-x-2 p-2 bg-white rounded border border-gray-300 focus:outline-none focus:border-blue-500"
160275 >
276+ { searchPersonaOptions . includes ( searchPersona ) ? "" : < option value = { searchPersona } key = { searchPersona } className = "block text-left p-2 hover:bg-gray-100 cursor-pointer" >
277+ { searchPersona }
278+ </ option > }
161279 { searchPersonaOptions . map ( ( option , index ) => (
162280 < option value = { option } key = { option } className = "block text-left p-2 hover:bg-gray-100 cursor-pointer" >
163281 { option }
0 commit comments