1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package fr.cnes.doi.resource.admin;
20
21 import fr.cnes.doi.application.AdminApplication;
22 import static fr.cnes.doi.application.AdminApplication.TOKEN_TEMPLATE;
23 import fr.cnes.doi.db.AbstractTokenDBHelper;
24 import fr.cnes.doi.db.model.DOIUser;
25 import fr.cnes.doi.exception.DOIDbException;
26 import fr.cnes.doi.exception.DoiRuntimeException;
27 import fr.cnes.doi.exception.TokenSecurityException;
28 import fr.cnes.doi.plugin.PluginFactory;
29 import fr.cnes.doi.resource.AbstractResource;
30 import fr.cnes.doi.security.RoleAuthorizer;
31 import fr.cnes.doi.security.TokenSecurity;
32 import fr.cnes.doi.security.TokenSecurity.TimeUnit;
33 import fr.cnes.doi.settings.Consts;
34 import fr.cnes.doi.settings.DoiSettings;
35 import fr.cnes.doi.settings.EmailSettings;
36 import fr.cnes.doi.utils.spec.Requirement;
37 import io.jsonwebtoken.Claims;
38 import io.jsonwebtoken.Jws;
39 import java.util.List;
40 import org.apache.logging.log4j.Level;
41 import org.apache.logging.log4j.Logger;
42 import org.restlet.data.Form;
43 import org.restlet.data.MediaType;
44 import org.restlet.data.Method;
45 import org.restlet.data.Status;
46 import org.restlet.ext.json.JsonRepresentation;
47 import org.restlet.ext.wadl.DocumentationInfo;
48 import org.restlet.ext.wadl.MethodInfo;
49 import org.restlet.ext.wadl.ParameterStyle;
50 import org.restlet.ext.wadl.RepresentationInfo;
51 import org.restlet.representation.Representation;
52 import org.restlet.resource.Delete;
53 import org.restlet.resource.Get;
54 import org.restlet.resource.Post;
55 import org.restlet.resource.ResourceException;
56
57
58
59
60
61
62 @Requirement(reqId = Requirement.DOI_INTER_040, reqName = Requirement.DOI_INTER_040_NAME)
63 public class TokenResource extends AbstractResource {
64
65
66
67
68 public static final String IDENTIFIER_PARAMETER = "identifier";
69
70
71
72
73 public static final String PROJECT_ID_PARAMETER = "projectID";
74
75
76
77
78 public static final String UNIT_OF_TIME_PARAMETER = "typeOfTime";
79
80
81
82
83 public static final String AMOUNT_OF_TIME_PARAMETER = "amountTime";
84
85
86
87
88 private volatile String tokenParam;
89
90
91
92
93 private volatile AbstractTokenDBHelper tokenDB;
94
95
96
97
98 private volatile Logger LOG;
99
100
101
102
103
104
105
106 @Override
107 protected void doInit() throws ResourceException {
108 super.doInit();
109 final AdminApplication app = (AdminApplication) getApplication();
110 LOG = app.getLog();
111 LOG.traceEntry();
112 setDescription("This resource handles the token");
113 this.tokenParam = getAttribute(TOKEN_TEMPLATE);
114 this.tokenDB = ((AdminApplication) this.getApplication()).getTokenDB();
115 LOG.debug("Token Param : {}", this.tokenParam);
116 LOG.traceExit();
117 }
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132 @Requirement(reqId = Requirement.DOI_SRV_150, reqName = Requirement.DOI_SRV_150_NAME)
133 @Post
134 public String createToken(final Form infoForm) {
135 LOG.traceEntry("Paramater : {}", infoForm);
136 final Form info = (infoForm == null) ? new Form() : infoForm;
137 try {
138 final String user = this.getClientInfo().getUser().getIdentifier();
139 LOG.debug("Identified user : {}", user);
140 final String userID;
141 if (isInRole(RoleAuthorizer.ROLE_ADMIN)) {
142
143 LOG.debug("User {} is admin", user);
144 userID = info.getFirstValue(IDENTIFIER_PARAMETER, user);
145 } else {
146
147 userID = user;
148 }
149 final String projectID = info.getFirstValue(PROJECT_ID_PARAMETER, null);
150 final String defaultTimeUnit = DoiSettings.getInstance().getString(
151 Consts.TOKEN_EXPIRATION_UNIT,
152 String.valueOf(TokenSecurity.TimeUnit.HOUR.getTimeUnit())
153 );
154 final String defaultTimeDelay = DoiSettings.getInstance().getString(
155 Consts.TOKEN_EXPIRATION_DELAY, "1");
156
157 final String timeParam = info.getFirstValue(UNIT_OF_TIME_PARAMETER, defaultTimeUnit);
158 final int timeUnit = Integer.parseInt(timeParam);
159 final TimeUnit unit = TokenSecurity.TimeUnit.getTimeUnitFrom(timeUnit);
160
161 final int amount = Integer.parseInt(defaultTimeDelay);
162
163 final String tokenJwt;
164 if (projectID == null) {
165 tokenJwt = TokenSecurity.getInstance().generate(
166 userID,
167 unit,
168 amount
169 );
170 } else {
171 tokenJwt = TokenSecurity.getInstance().generate(
172 userID,
173 Integer.parseInt(projectID),
174 unit,
175 amount
176 );
177 }
178
179 LOG.info("Token created {} for project {} during {} {}",
180 tokenJwt, projectID, amount, unit.name());
181
182 if (this.tokenDB.addToken(tokenJwt)) {
183 sendTokenToUser(user, userID, tokenJwt, amount, timeUnit);
184 }
185
186 return LOG.traceExit(tokenJwt);
187 } catch (TokenSecurityException ex) {
188 throw LOG.throwing(Level.INFO, new ResourceException(ex.getStatus(), ex.getMessage(),
189 ex));
190 }
191 }
192
193
194
195
196
197
198
199
200
201
202
203 private void sendTokenToUser(final String userAdmin, final String userID, final String token,
204 final int amount, final int timeUnit) {
205 if (!userAdmin.equals(userID)) {
206 try {
207 final StringBuilder builderMsg = new StringBuilder();
208 builderMsg.append("The administrator ").append(userAdmin)
209 .append(" has created a token for you:\n\n").append(token).append("\n\n")
210 .append("This token is valid during ").append(amount).append(" ")
211 .append(TokenSecurity.TimeUnit.getTimeUnitFrom(timeUnit).name());
212 final List<DOIUser> doiUsers = PluginFactory.getUserManagement().getUsers();
213 String email = "";
214 for (final DOIUser doiUser : doiUsers) {
215 if (doiUser.getUsername().equals(userID)) {
216 email = doiUser.getEmail();
217 break;
218 }
219 }
220 if (email.isEmpty()) {
221 LOG.error("Email is not set for {}", userID);
222 }
223 EmailSettings.getInstance().sendMessage("Creating Token", builderMsg.toString(),
224 email);
225 } catch (DOIDbException ex) {
226 LOG.error(ex);
227 }
228 }
229 }
230
231
232
233
234
235
236 @Requirement(reqId = Requirement.DOI_SRV_180, reqName = Requirement.DOI_SRV_180_NAME)
237 @Get
238 public Representation getTokenInformation() {
239 LOG.traceEntry();
240 try {
241 final Jws<Claims> jws = TokenSecurity.getInstance()
242 .getTokenInformation(this.tokenParam);
243 return LOG.traceExit(new JsonRepresentation(jws));
244 } catch (DoiRuntimeException ex) {
245 throw LOG.throwing(Level.INFO, new ResourceException(Status.CLIENT_ERROR_BAD_REQUEST,
246 ex));
247 }
248 }
249
250
251
252
253 @Requirement(reqId = Requirement.DOI_INTER_040, reqName = Requirement.DOI_INTER_040_NAME)
254 @Delete
255 public void deleteToken() {
256 LOG.traceEntry();
257 this.tokenDB.deleteToken(this.tokenParam);
258 }
259
260
261
262
263
264
265 @Requirement(reqId = Requirement.DOI_DOC_010, reqName = Requirement.DOI_DOC_010_NAME)
266 private RepresentationInfo jsonRepresentation() {
267 final RepresentationInfo repInfo = new RepresentationInfo();
268 repInfo.setMediaType(MediaType.APPLICATION_JSON);
269 final DocumentationInfo docInfo = new DocumentationInfo();
270 docInfo.setTitle("Json Representation");
271 docInfo.setTextContent("The representation contains informations about the token.");
272 repInfo.setDocumentation(docInfo);
273 return repInfo;
274 }
275
276
277
278
279
280
281 @Requirement(reqId = Requirement.DOI_DOC_010, reqName = Requirement.DOI_DOC_010_NAME)
282 @Override
283 protected void describeGet(final MethodInfo info) {
284 info.setName(Method.GET);
285 info.setDocumentation("Get information about a specific token");
286 addRequestDocToMethod(info, createQueryParamDoc(
287 TOKEN_TEMPLATE, ParameterStyle.TEMPLATE,
288 "token", true, "xs:string")
289 );
290 addResponseDocToMethod(info, createResponseDoc(
291 Status.SUCCESS_OK, "Operation successful", jsonRepresentation())
292 );
293 addResponseDocToMethod(info, createResponseDoc(
294 Status.CLIENT_ERROR_BAD_REQUEST, "Wrong token")
295 );
296 }
297
298
299
300
301
302
303 @Requirement(reqId = Requirement.DOI_DOC_010, reqName = Requirement.DOI_DOC_010_NAME)
304 @Override
305 protected void describePost(final MethodInfo info) {
306 info.setName(Method.POST);
307 info.setDocumentation("Creates a token");
308 addRequestDocToMethod(info, createQueryParamDoc(
309 IDENTIFIER_PARAMETER, ParameterStyle.MATRIX,
310 "User ID of the operator that creates the token", true, "xs:string")
311 );
312 addRequestDocToMethod(info, createQueryParamDoc(
313 PROJECT_ID_PARAMETER, ParameterStyle.MATRIX,
314 "Token for a specific project", true, "xs:string")
315 );
316 addRequestDocToMethod(info, createQueryParamDoc(
317 UNIT_OF_TIME_PARAMETER, ParameterStyle.MATRIX,
318 "Unit of time used to define the expiration time of the token",
319 false, "xs:int")
320 );
321 addResponseDocToMethod(info, createResponseDoc(
322 Status.SUCCESS_OK, "Operation successful",
323 stringRepresentation())
324 );
325 addResponseDocToMethod(info, createResponseDoc(
326 Status.CLIENT_ERROR_BAD_REQUEST, "Submitted values are not valid")
327 );
328 }
329
330 }