12
12
package org .opensearch .security .action .apitokens ;
13
13
14
14
import java .io .IOException ;
15
+ import java .nio .file .Path ;
15
16
import java .time .Instant ;
16
17
import java .util .Collections ;
17
18
import java .util .List ;
24
25
import org .apache .logging .log4j .Logger ;
25
26
26
27
import org .opensearch .client .node .NodeClient ;
28
+ import org .opensearch .cluster .metadata .IndexNameExpressionResolver ;
29
+ import org .opensearch .cluster .service .ClusterService ;
30
+ import org .opensearch .common .settings .Settings ;
31
+ import org .opensearch .common .util .concurrent .ThreadContext ;
27
32
import org .opensearch .core .action .ActionListener ;
28
33
import org .opensearch .core .rest .RestStatus ;
29
34
import org .opensearch .core .xcontent .XContentBuilder ;
30
35
import org .opensearch .rest .BaseRestHandler ;
31
36
import org .opensearch .rest .BytesRestResponse ;
32
37
import org .opensearch .rest .RestChannel ;
33
- import org .opensearch .rest .RestHandler ;
34
38
import org .opensearch .rest .RestRequest ;
39
+ import org .opensearch .security .auditlog .AuditLog ;
40
+ import org .opensearch .security .configuration .AdminDNs ;
41
+ import org .opensearch .security .configuration .ConfigurationRepository ;
42
+ import org .opensearch .security .dlic .rest .api .Endpoint ;
43
+ import org .opensearch .security .dlic .rest .api .RestApiAdminPrivilegesEvaluator ;
44
+ import org .opensearch .security .dlic .rest .api .RestApiPrivilegesEvaluator ;
45
+ import org .opensearch .security .dlic .rest .api .SecurityApiDependencies ;
46
+ import org .opensearch .security .dlic .rest .support .Utils ;
47
+ import org .opensearch .security .privileges .PrivilegesEvaluator ;
48
+ import org .opensearch .security .ssl .transport .PrincipalExtractor ;
49
+ import org .opensearch .security .support .ConfigConstants ;
50
+ import org .opensearch .threadpool .ThreadPool ;
35
51
36
52
import static org .opensearch .rest .RestRequest .Method .DELETE ;
37
53
import static org .opensearch .rest .RestRequest .Method .GET ;
44
60
import static org .opensearch .security .action .apitokens .ApiToken .INDEX_PERMISSIONS_FIELD ;
45
61
import static org .opensearch .security .action .apitokens .ApiToken .NAME_FIELD ;
46
62
import static org .opensearch .security .dlic .rest .support .Utils .addRoutesPrefix ;
63
+ import static org .opensearch .security .support .ConfigConstants .SECURITY_RESTAPI_ADMIN_ENABLED ;
47
64
import static org .opensearch .security .util .ParsingUtils .safeMapList ;
48
65
import static org .opensearch .security .util .ParsingUtils .safeStringList ;
49
66
50
67
public class ApiTokenAction extends BaseRestHandler {
51
- private ApiTokenRepository apiTokenRepository ;
68
+ private final ApiTokenRepository apiTokenRepository ;
52
69
public Logger log = LogManager .getLogger (this .getClass ());
53
-
54
- private static final List <RestHandler .Route > ROUTES = addRoutesPrefix (
55
- ImmutableList .of (
56
- new RestHandler .Route (POST , "/apitokens" ),
57
- new RestHandler .Route (DELETE , "/apitokens" ),
58
- new RestHandler .Route (GET , "/apitokens" )
59
- )
70
+ private final ThreadPool threadPool ;
71
+ private final ConfigurationRepository configurationRepository ;
72
+ private final PrivilegesEvaluator privilegesEvaluator ;
73
+ private final SecurityApiDependencies securityApiDependencies ;
74
+ private final ClusterService clusterService ;
75
+ private final IndexNameExpressionResolver indexNameExpressionResolver ;
76
+
77
+ private static final List <Route > ROUTES = addRoutesPrefix (
78
+ ImmutableList .of (new Route (POST , "/apitokens" ), new Route (DELETE , "/apitokens" ), new Route (GET , "/apitokens" ))
60
79
);
61
80
62
- public ApiTokenAction (ApiTokenRepository apiTokenRepository ) {
81
+ public ApiTokenAction (
82
+ ThreadPool threadpool ,
83
+ ConfigurationRepository configurationRepository ,
84
+ PrivilegesEvaluator privilegesEvaluator ,
85
+ Settings settings ,
86
+ AdminDNs adminDns ,
87
+ AuditLog auditLog ,
88
+ Path configPath ,
89
+ PrincipalExtractor principalExtractor ,
90
+ ApiTokenRepository apiTokenRepository ,
91
+ ClusterService clusterService ,
92
+ IndexNameExpressionResolver indexNameExpressionResolver
93
+ ) {
63
94
this .apiTokenRepository = apiTokenRepository ;
95
+ this .threadPool = threadpool ;
96
+ this .configurationRepository = configurationRepository ;
97
+ this .privilegesEvaluator = privilegesEvaluator ;
98
+ this .securityApiDependencies = new SecurityApiDependencies (
99
+ adminDns ,
100
+ configurationRepository ,
101
+ privilegesEvaluator ,
102
+ new RestApiPrivilegesEvaluator (settings , adminDns , privilegesEvaluator , principalExtractor , configPath , threadPool ),
103
+ new RestApiAdminPrivilegesEvaluator (
104
+ threadPool .getThreadContext (),
105
+ privilegesEvaluator ,
106
+ adminDns ,
107
+ settings .getAsBoolean (SECURITY_RESTAPI_ADMIN_ENABLED , false )
108
+ ),
109
+ auditLog ,
110
+ settings
111
+ );
112
+ this .clusterService = clusterService ;
113
+ this .indexNameExpressionResolver = indexNameExpressionResolver ;
64
114
}
65
115
66
116
@ Override
@@ -69,22 +119,28 @@ public String getName() {
69
119
}
70
120
71
121
@ Override
72
- public List <RestHandler . Route > routes () {
122
+ public List <Route > routes () {
73
123
return ROUTES ;
74
124
}
75
125
76
126
@ Override
77
127
protected RestChannelConsumer prepareRequest (final RestRequest request , final NodeClient client ) throws IOException {
78
- // TODO: Authorize this API properly
79
- switch (request .method ()) {
80
- case POST :
81
- return handlePost (request , client );
82
- case DELETE :
83
- return handleDelete (request , client );
84
- case GET :
85
- return handleGet (request , client );
86
- default :
87
- throw new IllegalArgumentException (request .method () + " not supported" );
128
+ authorizeSecurityAccess (request );
129
+ return doPrepareRequest (request , client );
130
+ }
131
+
132
+ RestChannelConsumer doPrepareRequest (RestRequest request , NodeClient client ) {
133
+ final var originalUserAndRemoteAddress = Utils .userAndRemoteAddressFrom (client .threadPool ().getThreadContext ());
134
+ try (final ThreadContext .StoredContext ctx = client .threadPool ().getThreadContext ().stashContext ()) {
135
+ client .threadPool ()
136
+ .getThreadContext ()
137
+ .putTransient (ConfigConstants .OPENDISTRO_SECURITY_USER , originalUserAndRemoteAddress .getLeft ());
138
+ return switch (request .method ()) {
139
+ case POST -> handlePost (request , client );
140
+ case DELETE -> handleDelete (request , client );
141
+ case GET -> handleGet (request , client );
142
+ default -> throw new IllegalArgumentException (request .method () + " not supported" );
143
+ };
88
144
}
89
145
}
90
146
@@ -119,8 +175,6 @@ private RestChannelConsumer handleGet(RestRequest request, NodeClient client) {
119
175
120
176
private RestChannelConsumer handlePost (RestRequest request , NodeClient client ) {
121
177
return channel -> {
122
- final XContentBuilder builder = channel .newBuilder ();
123
- BytesRestResponse response ;
124
178
try {
125
179
final Map <String , Object > requestBody = request .contentOrSourceParamParser ().map ();
126
180
validateRequestParameters (requestBody );
@@ -245,8 +299,6 @@ void validateIndexPermissionsList(List<Map<String, Object>> indexPermsList) {
245
299
246
300
private RestChannelConsumer handleDelete (RestRequest request , NodeClient client ) {
247
301
return channel -> {
248
- final XContentBuilder builder = channel .newBuilder ();
249
- BytesRestResponse response ;
250
302
try {
251
303
final Map <String , Object > requestBody = request .contentOrSourceParamParser ().map ();
252
304
@@ -295,4 +347,11 @@ private void sendErrorResponse(RestChannel channel, RestStatus status, String er
295
347
}
296
348
}
297
349
350
+ protected void authorizeSecurityAccess (RestRequest request ) throws IOException {
351
+ // Check if user has security API access
352
+ if (!(securityApiDependencies .restApiAdminPrivilegesEvaluator ().isCurrentUserAdminFor (Endpoint .APITOKENS )
353
+ || securityApiDependencies .restApiPrivilegesEvaluator ().checkAccessPermissions (request , Endpoint .APITOKENS ) == null )) {
354
+ throw new SecurityException ("User does not have required security API access" );
355
+ }
356
+ }
298
357
}
0 commit comments