Skip to content

Commit 3177c34

Browse files
authored
Scaffolding for POST/DELETE/GET api tokens calls (#4921)
Signed-off-by: Derek Ho <dxho@amazon.com>
1 parent 6ae7090 commit 3177c34

File tree

13 files changed

+1275
-8
lines changed

13 files changed

+1275
-8
lines changed

src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
import org.opensearch.search.internal.ReaderContext;
132132
import org.opensearch.search.internal.SearchContext;
133133
import org.opensearch.search.query.QuerySearchResult;
134+
import org.opensearch.security.action.apitokens.ApiTokenAction;
134135
import org.opensearch.security.action.configupdate.ConfigUpdateAction;
135136
import org.opensearch.security.action.configupdate.TransportConfigUpdateAction;
136137
import org.opensearch.security.action.onbehalf.CreateOnBehalfOfTokenAction;
@@ -635,6 +636,7 @@ public List<RestHandler> getRestHandlers(
635636
)
636637
);
637638
handlers.add(new CreateOnBehalfOfTokenAction(tokenManager));
639+
handlers.add(new ApiTokenAction(cs, threadPool, localClient));
638640
handlers.addAll(
639641
SecurityRestApiActions.getHandler(
640642
settings,
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
*
4+
* The OpenSearch Contributors require contributions made to
5+
* this file be licensed under the Apache-2.0 license or a
6+
* compatible open source license.
7+
*
8+
* Modifications Copyright OpenSearch Contributors. See
9+
* GitHub history for details.
10+
*/
11+
12+
package org.opensearch.security.action.apitokens;
13+
14+
import java.io.IOException;
15+
import java.time.Instant;
16+
import java.util.ArrayList;
17+
import java.util.List;
18+
19+
import org.opensearch.core.xcontent.ToXContent;
20+
import org.opensearch.core.xcontent.XContentBuilder;
21+
import org.opensearch.core.xcontent.XContentParser;
22+
23+
public class ApiToken implements ToXContent {
24+
public static final String NAME_FIELD = "name";
25+
public static final String JTI_FIELD = "jti";
26+
public static final String CREATION_TIME_FIELD = "creation_time";
27+
public static final String CLUSTER_PERMISSIONS_FIELD = "cluster_permissions";
28+
public static final String INDEX_PERMISSIONS_FIELD = "index_permissions";
29+
public static final String INDEX_PATTERN_FIELD = "index_pattern";
30+
public static final String ALLOWED_ACTIONS_FIELD = "allowed_actions";
31+
32+
private String name;
33+
private final String jti;
34+
private final Instant creationTime;
35+
private List<String> clusterPermissions;
36+
private List<IndexPermission> indexPermissions;
37+
38+
public ApiToken(String name, String jti, List<String> clusterPermissions, List<IndexPermission> indexPermissions) {
39+
this.creationTime = Instant.now();
40+
this.name = name;
41+
this.jti = jti;
42+
this.clusterPermissions = clusterPermissions;
43+
this.indexPermissions = indexPermissions;
44+
45+
}
46+
47+
public ApiToken(
48+
String description,
49+
String jti,
50+
List<String> clusterPermissions,
51+
List<IndexPermission> indexPermissions,
52+
Instant creationTime
53+
) {
54+
this.name = description;
55+
this.jti = jti;
56+
this.clusterPermissions = clusterPermissions;
57+
this.indexPermissions = indexPermissions;
58+
this.creationTime = creationTime;
59+
60+
}
61+
62+
public static class IndexPermission implements ToXContent {
63+
private final List<String> indexPatterns;
64+
private final List<String> allowedActions;
65+
66+
public IndexPermission(List<String> indexPatterns, List<String> allowedActions) {
67+
this.indexPatterns = indexPatterns;
68+
this.allowedActions = allowedActions;
69+
}
70+
71+
public List<String> getAllowedActions() {
72+
return allowedActions;
73+
}
74+
75+
public List<String> getIndexPatterns() {
76+
return indexPatterns;
77+
}
78+
79+
@Override
80+
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
81+
builder.startObject();
82+
builder.array(INDEX_PATTERN_FIELD, indexPatterns.toArray(new String[0]));
83+
builder.array(ALLOWED_ACTIONS_FIELD, allowedActions.toArray(new String[0]));
84+
builder.endObject();
85+
return builder;
86+
}
87+
}
88+
89+
/**
90+
* Class represents an API token.
91+
* Expected class structure
92+
* {
93+
* name: "token_name",
94+
* jti: "encrypted_token",
95+
* creation_time: 1234567890,
96+
* cluster_permissions: ["cluster_permission1", "cluster_permission2"],
97+
* index_permissions: [
98+
* {
99+
* index_pattern: ["index_pattern1", "index_pattern2"],
100+
* allowed_actions: ["allowed_action1", "allowed_action2"]
101+
* }
102+
* ],
103+
* expiration: 1234567890
104+
* }
105+
*/
106+
public static ApiToken fromXContent(XContentParser parser) throws IOException {
107+
String name = null;
108+
String jti = null;
109+
List<String> clusterPermissions = new ArrayList<>();
110+
List<IndexPermission> indexPermissions = new ArrayList<>();
111+
Instant creationTime = null;
112+
113+
XContentParser.Token token;
114+
String currentFieldName = null;
115+
116+
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
117+
if (token == XContentParser.Token.FIELD_NAME) {
118+
currentFieldName = parser.currentName();
119+
} else if (token.isValue()) {
120+
switch (currentFieldName) {
121+
case NAME_FIELD:
122+
name = parser.text();
123+
break;
124+
case JTI_FIELD:
125+
jti = parser.text();
126+
break;
127+
case CREATION_TIME_FIELD:
128+
creationTime = Instant.ofEpochMilli(parser.longValue());
129+
break;
130+
}
131+
} else if (token == XContentParser.Token.START_ARRAY) {
132+
switch (currentFieldName) {
133+
case CLUSTER_PERMISSIONS_FIELD:
134+
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
135+
clusterPermissions.add(parser.text());
136+
}
137+
break;
138+
case INDEX_PERMISSIONS_FIELD:
139+
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
140+
if (parser.currentToken() == XContentParser.Token.START_OBJECT) {
141+
indexPermissions.add(parseIndexPermission(parser));
142+
}
143+
}
144+
break;
145+
}
146+
}
147+
}
148+
149+
return new ApiToken(name, jti, clusterPermissions, indexPermissions, creationTime);
150+
}
151+
152+
private static IndexPermission parseIndexPermission(XContentParser parser) throws IOException {
153+
List<String> indexPatterns = new ArrayList<>();
154+
List<String> allowedActions = new ArrayList<>();
155+
156+
String currentFieldName = null;
157+
XContentParser.Token token;
158+
159+
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
160+
if (token == XContentParser.Token.FIELD_NAME) {
161+
currentFieldName = parser.currentName();
162+
} else if (token == XContentParser.Token.START_ARRAY) {
163+
switch (currentFieldName) {
164+
case INDEX_PATTERN_FIELD:
165+
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
166+
indexPatterns.add(parser.text());
167+
}
168+
break;
169+
case ALLOWED_ACTIONS_FIELD:
170+
while (parser.nextToken() != XContentParser.Token.END_ARRAY) {
171+
allowedActions.add(parser.text());
172+
}
173+
break;
174+
}
175+
}
176+
}
177+
178+
return new IndexPermission(indexPatterns, allowedActions);
179+
}
180+
181+
public String getName() {
182+
return name;
183+
}
184+
185+
public void setName(String name) {
186+
this.name = name;
187+
}
188+
189+
public String getJti() {
190+
return jti;
191+
}
192+
193+
public Instant getCreationTime() {
194+
return creationTime;
195+
}
196+
197+
public List<String> getClusterPermissions() {
198+
return clusterPermissions;
199+
}
200+
201+
public void setClusterPermissions(List<String> clusterPermissions) {
202+
this.clusterPermissions = clusterPermissions;
203+
}
204+
205+
@Override
206+
public XContentBuilder toXContent(XContentBuilder xContentBuilder, ToXContent.Params params) throws IOException {
207+
xContentBuilder.startObject();
208+
xContentBuilder.field(NAME_FIELD, name);
209+
xContentBuilder.field(JTI_FIELD, jti);
210+
xContentBuilder.field(CLUSTER_PERMISSIONS_FIELD, clusterPermissions);
211+
xContentBuilder.field(INDEX_PERMISSIONS_FIELD, indexPermissions);
212+
xContentBuilder.field(CREATION_TIME_FIELD, creationTime.toEpochMilli());
213+
xContentBuilder.endObject();
214+
return xContentBuilder;
215+
}
216+
217+
public List<IndexPermission> getIndexPermissions() {
218+
return indexPermissions;
219+
}
220+
221+
public void setIndexPermissions(List<IndexPermission> indexPermissions) {
222+
this.indexPermissions = indexPermissions;
223+
}
224+
}

0 commit comments

Comments
 (0)