16
16
import static org .opensearch .ad .settings .AnomalyDetectorSettings .AD_FILTER_BY_BACKEND_ROLES ;
17
17
import static org .opensearch .timeseries .util .ParseUtils .checkFilterByBackendRoles ;
18
18
import static org .opensearch .timeseries .util .ParseUtils .getConfig ;
19
+ import static org .opensearch .timeseries .util .ParseUtils .verifyResourceAccessAndProcessRequest ;
19
20
import static org .opensearch .timeseries .util .RestHandlerUtils .wrapRestActionListener ;
20
21
21
22
import java .util .List ;
27
28
import org .opensearch .action .support .ActionFilters ;
28
29
import org .opensearch .action .support .HandledTransportAction ;
29
30
import org .opensearch .action .support .WriteRequest ;
31
+ import org .opensearch .ad .constant .ADResourceScope ;
30
32
import org .opensearch .ad .constant .ConfigConstants ;
31
33
import org .opensearch .ad .indices .ADIndexManagement ;
32
34
import org .opensearch .ad .model .AnomalyDetector ;
52
54
import org .opensearch .timeseries .util .SecurityClientUtil ;
53
55
import org .opensearch .transport .TransportService ;
54
56
import org .opensearch .transport .client .Client ;
57
+ import org .opensearch .transport .client .node .NodeClient ;
55
58
56
59
public class IndexAnomalyDetectorTransportAction extends HandledTransportAction <IndexAnomalyDetectorRequest , IndexAnomalyDetectorResponse > {
57
60
private static final Logger LOG = LogManager .getLogger (IndexAnomalyDetectorTransportAction .class );
@@ -66,6 +69,7 @@ public class IndexAnomalyDetectorTransportAction extends HandledTransportAction<
66
69
private final SearchFeatureDao searchFeatureDao ;
67
70
private final Settings settings ;
68
71
private final boolean resourceSharingEnabled ;
72
+ private final NodeClient nodeClient ;
69
73
70
74
@ Inject
71
75
public IndexAnomalyDetectorTransportAction (
@@ -78,7 +82,8 @@ public IndexAnomalyDetectorTransportAction(
78
82
ADIndexManagement anomalyDetectionIndices ,
79
83
NamedXContentRegistry xContentRegistry ,
80
84
ADTaskManager adTaskManager ,
81
- SearchFeatureDao searchFeatureDao
85
+ SearchFeatureDao searchFeatureDao ,
86
+ NodeClient nodeClient
82
87
) {
83
88
super (IndexAnomalyDetectorAction .NAME , transportService , actionFilters , IndexAnomalyDetectorRequest ::new );
84
89
this .client = client ;
@@ -94,6 +99,7 @@ public IndexAnomalyDetectorTransportAction(
94
99
this .settings = settings ;
95
100
this .resourceSharingEnabled = settings
96
101
.getAsBoolean (ConfigConstants .OPENSEARCH_RESOURCE_SHARING_ENABLED , ConfigConstants .OPENSEARCH_RESOURCE_SHARING_ENABLED_DEFAULT );
102
+ this .nodeClient = nodeClient ;
97
103
}
98
104
99
105
@ Override
@@ -103,7 +109,29 @@ protected void doExecute(Task task, IndexAnomalyDetectorRequest request, ActionL
103
109
RestRequest .Method method = request .getMethod ();
104
110
String errorMessage = method == RestRequest .Method .PUT ? FAIL_TO_UPDATE_DETECTOR : FAIL_TO_CREATE_DETECTOR ;
105
111
ActionListener <IndexAnomalyDetectorResponse > listener = wrapRestActionListener (actionListener , errorMessage );
112
+
106
113
try (ThreadContext .StoredContext context = client .threadPool ().getThreadContext ().stashContext ()) {
114
+ if (resourceSharingEnabled ) {
115
+ // Call verifyResourceAccessAndProcessRequest before proceeding
116
+ verifyResourceAccessAndProcessRequest (
117
+ user ,
118
+ detectorId ,
119
+ ADResourceScope .AD_FULL_ACCESS .value (),
120
+ nodeClient ,
121
+ settings ,
122
+ listener ,
123
+ args -> indexDetector (
124
+ user ,
125
+ detectorId ,
126
+ method ,
127
+ listener ,
128
+ detector -> adExecute (request , user , detector , context , listener )
129
+ ) // Execute only if access is granted
130
+ );
131
+ return ;
132
+ }
133
+
134
+ // Proceed with normal execution if resource sharing is not enabled
107
135
resolveUserAndExecute (user , detectorId , method , listener , (detector ) -> adExecute (request , user , detector , context , listener ));
108
136
} catch (Exception e ) {
109
137
LOG .error (e );
@@ -119,44 +147,51 @@ private void resolveUserAndExecute(
119
147
Consumer <AnomalyDetector > function
120
148
) {
121
149
try {
122
- // If resource sharing flag is enabled then access evaluation will be performed at DLS level
123
- if (!resourceSharingEnabled && filterByEnabled ) {
124
- // Check if user has backend roles
125
- // When filter by is enabled, block users creating/updating detectors who do not have backend roles.
150
+ if (filterByEnabled ) {
126
151
String error = checkFilterByBackendRoles (requestedUser );
127
152
if (error != null ) {
128
153
listener .onFailure (new TimeSeriesException (error ));
129
154
return ;
130
155
}
131
156
}
132
- if (method == RestRequest .Method .PUT ) {
133
- // requestedUser == null means security is disabled or user is superadmin. In this case we don't need to
134
- // check if request user have access to the detector or not. But we still need to get current detector for
135
- // this case, so we can keep current detector's user data.
136
- boolean filterByBackendRole = requestedUser == null ? false : filterByEnabled ;
137
- // Update detector request, check if user has permissions to update the detector
138
- // Get detector and verify backend roles
139
- getConfig (
140
- requestedUser ,
141
- detectorId ,
142
- listener ,
143
- function ,
144
- client ,
145
- clusterService ,
146
- xContentRegistry ,
147
- filterByBackendRole ,
148
- AnomalyDetector .class ,
149
- resourceSharingEnabled
150
- );
151
- } else {
152
- // Create Detector. No need to get current detector.
153
- function .accept (null );
154
- }
157
+
158
+ indexDetector (requestedUser , detectorId , method , listener , function );
155
159
} catch (Exception e ) {
156
160
listener .onFailure (e );
157
161
}
158
162
}
159
163
164
+ private void indexDetector (
165
+ User requestedUser ,
166
+ String detectorId ,
167
+ RestRequest .Method method ,
168
+ ActionListener <IndexAnomalyDetectorResponse > listener ,
169
+ Consumer <AnomalyDetector > function
170
+ ) {
171
+ if (method == RestRequest .Method .PUT ) {
172
+ // requestedUser == null means security is disabled or user is superadmin. In this case we don't need to
173
+ // check if request user have access to the detector or not. But we still need to get current detector for
174
+ // this case, so we can keep current detector's user data.
175
+ boolean filterByBackendRole = requestedUser == null ? false : filterByEnabled ;
176
+ // Update detector request, check if user has permissions to update the detector
177
+ // Get detector and verify backend roles
178
+ getConfig (
179
+ requestedUser ,
180
+ detectorId ,
181
+ listener ,
182
+ function ,
183
+ client ,
184
+ clusterService ,
185
+ xContentRegistry ,
186
+ filterByBackendRole ,
187
+ AnomalyDetector .class
188
+ );
189
+ } else {
190
+ // Create Detector. No need to get current detector.
191
+ function .accept (null );
192
+ }
193
+ }
194
+
160
195
protected void adExecute (
161
196
IndexAnomalyDetectorRequest request ,
162
197
User user ,
0 commit comments