1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.waarp.gateway.kernel.rest;
21
22 import com.fasterxml.jackson.databind.JsonNode;
23 import com.fasterxml.jackson.databind.node.ArrayNode;
24 import com.fasterxml.jackson.databind.node.ObjectNode;
25 import io.netty.buffer.Unpooled;
26 import io.netty.handler.codec.http.FullHttpRequest;
27 import io.netty.handler.codec.http.HttpHeaderNames;
28 import io.netty.handler.codec.http.HttpRequest;
29 import io.netty.handler.codec.http.HttpResponseStatus;
30 import io.netty.handler.codec.http.QueryStringDecoder;
31 import io.netty.handler.codec.http.QueryStringEncoder;
32 import io.netty.handler.codec.http.cookie.Cookie;
33 import io.netty.handler.codec.http.cookie.ServerCookieDecoder;
34 import org.joda.time.DateTime;
35 import org.joda.time.Duration;
36 import org.waarp.common.crypto.HmacSha256;
37 import org.waarp.common.exception.InvalidArgumentException;
38 import org.waarp.common.json.JsonHandler;
39 import org.waarp.common.logging.WaarpLogger;
40 import org.waarp.common.logging.WaarpLoggerFactory;
41 import org.waarp.common.role.RoleDefault;
42 import org.waarp.common.role.RoleDefault.ROLE;
43 import org.waarp.common.utility.ParametersChecker;
44 import org.waarp.gateway.kernel.exception.HttpIncorrectRequestException;
45 import org.waarp.gateway.kernel.exception.HttpInvalidAuthenticationException;
46 import org.waarp.gateway.kernel.rest.DataModelRestMethodHandler.COMMAND_TYPE;
47 import org.waarp.gateway.kernel.rest.HttpRestHandler.METHOD;
48
49 import java.util.Collections;
50 import java.util.Iterator;
51 import java.util.List;
52 import java.util.Map;
53 import java.util.Map.Entry;
54 import java.util.Set;
55 import java.util.TreeMap;
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 public class RestArgument {
73
74
75
76 private static final WaarpLogger logger =
77 WaarpLoggerFactory.getLogger(RestArgument.class);
78
79 public enum REST_GROUP {
80
81
82
83 ARGS_URI("uri"),
84
85
86
87 ARGS_HEADER("header"),
88
89
90
91 ARGS_COOKIE("cookie"),
92
93
94
95 ARGS_BODY("body"),
96
97
98
99 ARGS_ANSWER("answer");
100
101 public final String group;
102
103 REST_GROUP(final String group) {
104 this.group = group;
105 }
106 }
107
108 public enum REST_ROOT_FIELD {
109
110
111
112 ARG_PATH("path"),
113
114
115
116 ARG_BASEPATH("base"),
117
118
119
120
121
122
123 ARGS_SUBPATH("subpath"),
124
125
126
127 ARG_METHOD("X-method"),
128
129
130
131
132 ARG_HASBODY("hasBody"),
133
134
135
136 ARG_X_AUTH_KEY("X-Auth-Key"),
137
138
139
140 ARG_X_AUTH_USER("X-Auth-User"),
141
142
143
144 ARG_X_AUTH_INTERNALKEY("X-Auth-InternalKey"),
145
146
147
148
149 ARG_X_AUTH_TIMESTAMP("X-Auth-Timestamp"),
150
151
152
153 ARG_X_AUTH_ROLE("X-Auth-Role"), JSON_STATUSCODE("code"),
154 JSON_STATUSMESSAGE("message"), JSON_COMMAND("command"),
155 JSON_DETAIL("detail");
156
157 public final String field;
158
159 REST_ROOT_FIELD(final String field) {
160 this.field = field;
161 }
162 }
163
164 public enum REST_FIELD {
165 JSON_RESULT("result"), JSON_PATH("path"), JSON_JSON("body"),
166 X_DETAILED_ALLOW("DetailedAllow"), X_ALLOW_URIS("UriAllowed"),
167 JSON_ID("_id");
168
169 public final String field;
170
171 REST_FIELD(final String field) {
172 this.field = field;
173 }
174 }
175
176 public enum DATAMODEL {
177 JSON_COUNT("count"), JSON_RESULTS("results"), JSON_FILTER("filter"),
178 JSON_LIMIT("limit");
179
180 public final String field;
181
182 DATAMODEL(final String field) {
183 this.field = field;
184 }
185 }
186
187 final ObjectNode arguments;
188
189
190
191
192
193
194
195 public RestArgument(final ObjectNode emptyArgument) {
196 if (emptyArgument == null) {
197 arguments = JsonHandler.createObjectNode();
198 } else {
199 arguments = emptyArgument;
200 }
201 }
202
203
204
205
206 public final void clean() {
207 arguments.removeAll();
208 }
209
210
211
212
213
214
215 public final void setRequest(final HttpRequest request) {
216 arguments.put(REST_ROOT_FIELD.ARG_HASBODY.field,
217 request instanceof FullHttpRequest &&
218 ((FullHttpRequest) request).content() !=
219 Unpooled.EMPTY_BUFFER);
220 arguments.put(REST_ROOT_FIELD.ARG_METHOD.field, request.method().name());
221 final QueryStringDecoder decoderQuery =
222 new QueryStringDecoder(request.uri());
223 final String path = decoderQuery.path();
224 arguments.put(REST_ROOT_FIELD.ARG_PATH.field, path);
225
226 String basepath = path;
227 int pos = basepath.indexOf('/');
228 if (pos >= 0) {
229 if (pos == 0) {
230 final int pos2 = basepath.indexOf('/', 1);
231 if (pos2 < 0) {
232 basepath = basepath.substring(1);
233 } else {
234 basepath = basepath.substring(1, pos2);
235 }
236 } else {
237 basepath = basepath.substring(0, pos);
238 }
239 }
240 arguments.put(REST_ROOT_FIELD.ARG_BASEPATH.field, basepath);
241
242 if (pos == 0) {
243 pos = path.indexOf('/', 1);
244 }
245 if (pos >= 0) {
246 int pos2 = path.indexOf('/', pos + 1);
247 if (pos2 > 0) {
248 final ArrayNode array =
249 arguments.putArray(REST_ROOT_FIELD.ARGS_SUBPATH.field);
250 while (pos2 > 0) {
251 array.add(path.substring(pos + 1, pos2));
252 pos = pos2;
253 pos2 = path.indexOf('/', pos + 1);
254 }
255 }
256 pos2 = path.indexOf('?', pos + 1);
257 if (pos2 > 0 && pos2 > pos + 1) {
258 ArrayNode array =
259 (ArrayNode) arguments.get(REST_ROOT_FIELD.ARGS_SUBPATH.field);
260 if (array == null) {
261 array = arguments.putArray(REST_ROOT_FIELD.ARGS_SUBPATH.field);
262 }
263 array.add(path.substring(pos + 1, pos2));
264 } else {
265 final String last = path.substring(pos + 1);
266 if (!last.isEmpty()) {
267 ArrayNode array =
268 (ArrayNode) arguments.get(REST_ROOT_FIELD.ARGS_SUBPATH.field);
269 if (array == null) {
270 array = arguments.putArray(REST_ROOT_FIELD.ARGS_SUBPATH.field);
271 }
272 array.add(last);
273 }
274 }
275 }
276 final Map<String, List<String>> map = decoderQuery.parameters();
277 final ObjectNode node = arguments.putObject(REST_GROUP.ARGS_URI.group);
278 for (final Entry<String, List<String>> entry : map.entrySet()) {
279 final String key = entry.getKey();
280 try {
281 ParametersChecker.checkSanityString(
282 entry.getValue().toArray(ParametersChecker.ZERO_ARRAY_STRING));
283 if (key.equalsIgnoreCase(REST_ROOT_FIELD.ARG_X_AUTH_KEY.field)) {
284 arguments.put(REST_ROOT_FIELD.ARG_X_AUTH_KEY.field,
285 entry.getValue().get(0));
286 continue;
287 }
288 if (key.equalsIgnoreCase(REST_ROOT_FIELD.ARG_X_AUTH_USER.field)) {
289 arguments.put(REST_ROOT_FIELD.ARG_X_AUTH_USER.field,
290 entry.getValue().get(0));
291 continue;
292 }
293 if (key.equalsIgnoreCase(REST_ROOT_FIELD.ARG_X_AUTH_TIMESTAMP.field)) {
294 arguments.put(REST_ROOT_FIELD.ARG_X_AUTH_TIMESTAMP.field,
295 entry.getValue().get(0));
296 continue;
297 }
298 final List<String> list = entry.getValue();
299 if (list.size() > 1) {
300 final ArrayNode array = node.putArray(key);
301 for (final String val : entry.getValue()) {
302 array.add(val);
303 }
304 } else if (list.isEmpty()) {
305 node.putNull(key);
306 } else {
307
308 node.put(key, list.get(0));
309 }
310 } catch (final InvalidArgumentException e) {
311 logger.error("Arguments incompatible with Security: " + entry.getKey(),
312 e);
313 }
314 }
315 }
316
317
318
319
320
321
322 public final void setFromArgument(final RestArgument source) {
323 if (source.arguments.has(REST_ROOT_FIELD.ARG_X_AUTH_USER.field)) {
324 arguments.put(REST_ROOT_FIELD.ARG_X_AUTH_USER.field,
325 source.arguments.get(REST_ROOT_FIELD.ARG_X_AUTH_USER.field)
326 .asText());
327 }
328 if (source.arguments.has(REST_ROOT_FIELD.ARG_METHOD.field)) {
329 arguments.put(REST_ROOT_FIELD.ARG_METHOD.field,
330 source.arguments.get(REST_ROOT_FIELD.ARG_METHOD.field)
331 .asText());
332 }
333 if (source.arguments.has(REST_ROOT_FIELD.ARG_PATH.field)) {
334 arguments.put(REST_ROOT_FIELD.ARG_PATH.field,
335 source.arguments.get(REST_ROOT_FIELD.ARG_PATH.field)
336 .asText());
337 }
338 if (source.arguments.has(REST_ROOT_FIELD.ARG_BASEPATH.field)) {
339 arguments.put(REST_ROOT_FIELD.ARG_BASEPATH.field,
340 source.arguments.get(REST_ROOT_FIELD.ARG_BASEPATH.field)
341 .asText());
342 }
343 if (source.arguments.has(REST_ROOT_FIELD.ARGS_SUBPATH.field)) {
344 arguments.putArray(REST_ROOT_FIELD.ARGS_SUBPATH.field).addAll(
345 (ArrayNode) source.arguments.get(REST_ROOT_FIELD.ARGS_SUBPATH.field));
346 }
347 if (source.arguments.has(REST_GROUP.ARGS_URI.group)) {
348 arguments.putObject(REST_GROUP.ARGS_URI.group).setAll(
349 (ObjectNode) source.arguments.get(REST_GROUP.ARGS_URI.group));
350 }
351 if (source.arguments.has(REST_GROUP.ARGS_COOKIE.group)) {
352 arguments.putObject(REST_GROUP.ARGS_COOKIE.group).setAll(
353 (ObjectNode) source.arguments.get(REST_GROUP.ARGS_COOKIE.group));
354 }
355
356 logger.debug("DEBUG: {}\n {}", arguments, source);
357 }
358
359
360
361
362 public final String getUri() {
363 return arguments.path(REST_ROOT_FIELD.ARG_PATH.field).asText();
364 }
365
366
367
368
369 public final String getBaseUri() {
370 return arguments.path(REST_ROOT_FIELD.ARG_BASEPATH.field).asText();
371 }
372
373
374
375
376
377 public final Iterator<JsonNode> getSubUri() {
378 return arguments.path(REST_ROOT_FIELD.ARGS_SUBPATH.field).elements();
379 }
380
381 public final int getSubUriSize() {
382 return arguments.path(REST_ROOT_FIELD.ARGS_SUBPATH.field).size();
383 }
384
385 public final void addSubUriToUriArgs(final String name, final int rank) {
386 final ObjectNode node = getUriArgs();
387 final JsonNode elt =
388 arguments.path(REST_ROOT_FIELD.ARGS_SUBPATH.field).get(rank);
389 if (elt != null) {
390 node.set(name, elt);
391 }
392 }
393
394 public final void addIdToUriArgs() {
395 addSubUriToUriArgs(REST_FIELD.JSON_ID.field, 0);
396 }
397
398 public final JsonNode getId() {
399 return getUriArgs().path(REST_FIELD.JSON_ID.field);
400 }
401
402 public static JsonNode getId(final ObjectNode node) {
403 return node.path(REST_FIELD.JSON_ID.field);
404 }
405
406 public final long getLimitFromUri() {
407 return getUriArgs().path(DATAMODEL.JSON_LIMIT.field).asLong(100);
408 }
409
410 public final String getXAuthKey() {
411 return arguments.path(REST_ROOT_FIELD.ARG_X_AUTH_KEY.field).asText();
412 }
413
414 public final String getXAuthUser() {
415 return arguments.path(REST_ROOT_FIELD.ARG_X_AUTH_USER.field).asText();
416 }
417
418 public final String getXAuthTimestamp() {
419 return arguments.path(REST_ROOT_FIELD.ARG_X_AUTH_TIMESTAMP.field).asText();
420 }
421
422 public final void setXAuthRole(final RoleDefault role) {
423 arguments.put(REST_ROOT_FIELD.ARG_X_AUTH_ROLE.field, role.getRoleAsByte());
424 }
425
426 public final ROLE getXAuthRole() {
427 final byte role =
428 (byte) arguments.get(REST_ROOT_FIELD.ARG_X_AUTH_ROLE.field).asInt();
429 return ROLE.fromByte(role);
430 }
431
432
433
434
435 public final ObjectNode getUriArgs() {
436 JsonNode node = arguments.path(REST_GROUP.ARGS_URI.group);
437 if (node == null || node.isMissingNode()) {
438 node = arguments.putObject(REST_GROUP.ARGS_URI.group);
439 }
440 return (ObjectNode) node;
441 }
442
443
444
445
446 public final METHOD getMethod() {
447 final String text =
448 arguments.path(REST_ROOT_FIELD.ARG_METHOD.field).asText();
449 if (ParametersChecker.isEmpty(text)) {
450 return METHOD.TRACE;
451 }
452 try {
453 return METHOD.valueOf(text);
454 } catch (final Exception e) {
455 return METHOD.TRACE;
456 }
457 }
458
459
460
461
462
463
464 public final void setHeaderArgs(final List<Entry<String, String>> list) {
465 ObjectNode node = (ObjectNode) arguments.get(REST_GROUP.ARGS_HEADER.group);
466 if (node == null || node.isMissingNode()) {
467 node = arguments.putObject(REST_GROUP.ARGS_HEADER.group);
468 }
469 for (final Entry<String, String> entry : list) {
470 try {
471 ParametersChecker.checkSanityString(entry.getValue());
472 final String key = entry.getKey();
473 if (!key.equals(HttpHeaderNames.COOKIE.toString())) {
474 if (key.equalsIgnoreCase(REST_ROOT_FIELD.ARG_X_AUTH_KEY.field)) {
475 arguments.put(REST_ROOT_FIELD.ARG_X_AUTH_KEY.field,
476 entry.getValue());
477 continue;
478 }
479 if (key.equalsIgnoreCase(REST_ROOT_FIELD.ARG_X_AUTH_USER.field)) {
480 arguments.put(REST_ROOT_FIELD.ARG_X_AUTH_USER.field,
481 entry.getValue());
482 continue;
483 }
484 if (key.equalsIgnoreCase(
485 REST_ROOT_FIELD.ARG_X_AUTH_TIMESTAMP.field)) {
486 arguments.put(REST_ROOT_FIELD.ARG_X_AUTH_TIMESTAMP.field,
487 entry.getValue());
488 continue;
489 }
490 node.put(key, entry.getValue());
491 }
492 } catch (final InvalidArgumentException e) {
493 logger.error("Arguments incompatible with Security: " + entry.getKey(),
494 e);
495 }
496 }
497 }
498
499
500
501
502
503
504 public final void setHeaderArgs(
505 final Iterator<Entry<CharSequence, CharSequence>> iterator) {
506 ObjectNode node = (ObjectNode) arguments.get(REST_GROUP.ARGS_HEADER.group);
507 if (node == null || node.isMissingNode()) {
508 node = arguments.putObject(REST_GROUP.ARGS_HEADER.group);
509 }
510 while (iterator.hasNext()) {
511 final Entry<CharSequence, CharSequence> entry = iterator.next();
512 try {
513 ParametersChecker.checkSanityString(entry.getValue().toString());
514 final String key = entry.getKey().toString();
515 if (!key.equals(HttpHeaderNames.COOKIE.toString())) {
516 if (key.equalsIgnoreCase(REST_ROOT_FIELD.ARG_X_AUTH_KEY.field)) {
517 arguments.put(REST_ROOT_FIELD.ARG_X_AUTH_KEY.field,
518 entry.getValue().toString());
519 continue;
520 }
521 if (key.equalsIgnoreCase(REST_ROOT_FIELD.ARG_X_AUTH_USER.field)) {
522 arguments.put(REST_ROOT_FIELD.ARG_X_AUTH_USER.field,
523 entry.getValue().toString());
524 continue;
525 }
526 if (key.equalsIgnoreCase(
527 REST_ROOT_FIELD.ARG_X_AUTH_TIMESTAMP.field)) {
528 arguments.put(REST_ROOT_FIELD.ARG_X_AUTH_TIMESTAMP.field,
529 entry.getValue().toString());
530 continue;
531 }
532 node.put(key, entry.getValue().toString());
533 }
534 } catch (final InvalidArgumentException e) {
535 logger.error("Arguments incompatible with Security: " + entry.getKey(),
536 e);
537 }
538 }
539 }
540
541
542
543
544 public final ObjectNode getHeaderArgs() {
545 JsonNode node = arguments.path(REST_GROUP.ARGS_HEADER.group);
546 if (node == null || node.isMissingNode()) {
547 node = arguments.putObject(REST_GROUP.ARGS_HEADER.group);
548 }
549 return (ObjectNode) node;
550 }
551
552
553
554
555 public final void methodFromUri() {
556 final JsonNode node = arguments.path(REST_GROUP.ARGS_URI.group)
557 .path(REST_ROOT_FIELD.ARG_METHOD.field);
558 if (!node.isMissingNode()) {
559
560 arguments.put(REST_ROOT_FIELD.ARG_METHOD.field, node.asText());
561 }
562 }
563
564
565
566
567 public final void methodFromHeader() {
568 final JsonNode node = arguments.path(REST_GROUP.ARGS_HEADER.group)
569 .path(REST_ROOT_FIELD.ARG_METHOD.field);
570 if (!node.isMissingNode()) {
571
572 arguments.put(REST_ROOT_FIELD.ARG_METHOD.field, node.asText());
573 }
574 }
575
576
577
578
579 public final void setCookieArgs(final String cookieString) {
580 final Set<Cookie> cookies;
581 if (cookieString == null) {
582 cookies = Collections.emptySet();
583 } else {
584 cookies = ServerCookieDecoder.LAX.decode(cookieString);
585 }
586 if (!cookies.isEmpty()) {
587 final ObjectNode node = arguments.putObject(REST_GROUP.ARGS_COOKIE.group);
588 for (final Cookie cookie : cookies) {
589 try {
590 ParametersChecker.checkSanityString(cookie.value());
591 node.put(cookie.name(), cookie.value());
592 } catch (final InvalidArgumentException e) {
593 logger.error("Arguments incompatible with Security: " + cookie.name(),
594 e);
595 }
596 }
597 }
598 }
599
600
601
602
603 public final ObjectNode getCookieArgs() {
604 JsonNode node = arguments.path(REST_GROUP.ARGS_COOKIE.group);
605 if (node == null || node.isMissingNode()) {
606 node = arguments.putObject(REST_GROUP.ARGS_COOKIE.group);
607 }
608 return (ObjectNode) node;
609 }
610
611
612
613
614 public final ObjectNode getBody() {
615 JsonNode node = arguments.path(REST_GROUP.ARGS_BODY.group);
616 if (node == null || node.isMissingNode()) {
617 node = arguments.putObject(REST_GROUP.ARGS_BODY.group);
618 }
619 return (ObjectNode) node;
620 }
621
622
623
624
625 public final ObjectNode getAnswer() {
626 JsonNode node = arguments.path(REST_GROUP.ARGS_ANSWER.group);
627 if (node == null || node.isMissingNode()) {
628 node = arguments.putObject(REST_GROUP.ARGS_ANSWER.group);
629 }
630 return (ObjectNode) node;
631 }
632
633 public final void addAnswer(final ObjectNode node) {
634 getAnswer().setAll(node);
635 }
636
637 public final void setResult(final HttpResponseStatus status) {
638 arguments.put(REST_ROOT_FIELD.JSON_STATUSMESSAGE.field,
639 status.reasonPhrase());
640 arguments.put(REST_ROOT_FIELD.JSON_STATUSCODE.field, status.code());
641 }
642
643
644
645
646 public final int getStatusCode() {
647 return arguments.path(REST_ROOT_FIELD.JSON_STATUSCODE.field).asInt();
648 }
649
650
651
652
653 public final String getStatusMessage() {
654 return arguments.path(REST_ROOT_FIELD.JSON_STATUSMESSAGE.field).asText();
655 }
656
657 public final void setDetail(final String detail) {
658 arguments.put(REST_ROOT_FIELD.JSON_DETAIL.field, detail);
659 }
660
661
662
663
664 public final String getDetail() {
665 return arguments.path(REST_ROOT_FIELD.JSON_DETAIL.field).asText();
666 }
667
668 public final void setCommand(final COMMAND_TYPE command) {
669 arguments.put(REST_ROOT_FIELD.JSON_COMMAND.field, command.name());
670 }
671
672 public final void setCommand(final String cmd) {
673 arguments.put(REST_ROOT_FIELD.JSON_COMMAND.field, cmd);
674 }
675
676
677
678
679
680 public final String getCommandField() {
681 return arguments.path(REST_ROOT_FIELD.JSON_COMMAND.field).asText();
682 }
683
684
685
686
687
688 public final COMMAND_TYPE getCommand() {
689 final String cmd =
690 arguments.path(REST_ROOT_FIELD.JSON_COMMAND.field).asText();
691 if (ParametersChecker.isNotEmpty(cmd)) {
692 try {
693 return COMMAND_TYPE.valueOf(cmd);
694 } catch (final Exception e) {
695 return null;
696 }
697 } else {
698 return null;
699 }
700 }
701
702
703
704
705 public final void addFilter(ObjectNode filter) {
706 if (filter == null) {
707 filter = JsonHandler.createObjectNode();
708 }
709 getAnswer().putObject(DATAMODEL.JSON_FILTER.field).setAll(filter);
710 }
711
712
713
714
715 public final ObjectNode getFilter() {
716 return (ObjectNode) getAnswer().path(DATAMODEL.JSON_FILTER.field);
717 }
718
719
720
721
722 public final ArrayNode getResults() {
723 JsonNode node = getAnswer().path(DATAMODEL.JSON_RESULTS.field);
724 if (node == null || node.isMissingNode()) {
725 node = getAnswer().putArray(DATAMODEL.JSON_RESULTS.field);
726 }
727 return (ArrayNode) node;
728 }
729
730
731
732
733
734 public final void addResult(final ObjectNode result) {
735 getResults().add(result);
736 }
737
738
739
740
741
742 public final void addCountLimit(final long count, final long limit) {
743 final ObjectNode node = getAnswer();
744 if (count >= 0) {
745 node.put(DATAMODEL.JSON_COUNT.field, count);
746 }
747 node.put(DATAMODEL.JSON_LIMIT.field, limit);
748 }
749
750
751
752
753 public final long getCount() {
754 return getAnswer().path(DATAMODEL.JSON_COUNT.field).asLong(-1);
755 }
756
757 public final long getLimit() {
758 return getAnswer().path(DATAMODEL.JSON_LIMIT.field).asLong(100);
759 }
760
761
762
763
764
765
766
767
768 public final void addOptions(final String allow, final String path,
769 final ArrayNode detailedAllow) {
770 final ObjectNode node = getAnswer();
771 node.put(HttpHeaderNames.ALLOW.toString(), allow);
772 node.put(REST_FIELD.X_ALLOW_URIS.field, path);
773 if (detailedAllow != null) {
774 node.putArray(REST_FIELD.X_DETAILED_ALLOW.field).addAll(detailedAllow);
775 }
776 }
777
778 public final String getAllowOption() {
779 return getAnswer().path(HttpHeaderNames.ALLOW.toString()).asText();
780 }
781
782 public final String getAllowUrisOption() {
783 return getAnswer().path(REST_FIELD.X_ALLOW_URIS.field).asText();
784 }
785
786 public final ArrayNode getDetailedAllowOption() {
787 final JsonNode node = getAnswer().path(REST_FIELD.X_DETAILED_ALLOW.field);
788 if (node.isMissingNode()) {
789 return JsonHandler.createArrayNode();
790 } else {
791 return (ArrayNode) node;
792 }
793 }
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811 public static String[] getBaseAuthent(final HmacSha256 hmacSha256,
812 final QueryStringEncoder encoder,
813 final String user,
814 final String extraKey)
815 throws HttpInvalidAuthenticationException {
816 final QueryStringDecoder decoderQuery =
817 new QueryStringDecoder(encoder.toString());
818 final Map<String, List<String>> map = decoderQuery.parameters();
819 final TreeMap<String, String> treeMap = new TreeMap<String, String>();
820 for (final Entry<String, List<String>> entry : map.entrySet()) {
821 final String keylower = entry.getKey().toLowerCase();
822 final List<String> values = entry.getValue();
823 if (values != null && !values.isEmpty()) {
824 final String last = values.get(values.size() - 1);
825 treeMap.put(keylower, last);
826 }
827 }
828 final DateTime date = new DateTime();
829 treeMap.put(REST_ROOT_FIELD.ARG_X_AUTH_TIMESTAMP.field.toLowerCase(),
830 date.toString());
831 if (user != null) {
832 treeMap.put(REST_ROOT_FIELD.ARG_X_AUTH_USER.field.toLowerCase(), user);
833 }
834 try {
835 final String key =
836 computeKey(hmacSha256, extraKey, treeMap, decoderQuery.path());
837 return new String[] { date.toString(), key };
838 } catch (final Exception e) {
839 throw new HttpInvalidAuthenticationException(e);
840 }
841
842 }
843
844
845
846
847
848
849
850
851 public final void checkTime(final long maxInterval)
852 throws HttpInvalidAuthenticationException {
853 final DateTime dateTime = new DateTime();
854 final String date = getXAuthTimestamp();
855 if (ParametersChecker.isNotEmpty(date)) {
856 final DateTime received = DateTime.parse(date);
857 if (maxInterval > 0) {
858 final Duration duration = new Duration(received, dateTime);
859 if (Math.abs(duration.getMillis()) >= maxInterval) {
860 throw new HttpInvalidAuthenticationException(
861 "timestamp is not compatible with the maximum delay allowed");
862 }
863 }
864 } else if (maxInterval > 0) {
865 throw new HttpInvalidAuthenticationException(
866 "timestamp absent while required");
867 }
868 }
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892 public final void checkBaseAuthent(final HmacSha256 hmacSha256,
893 final String extraKey,
894 final long maxInterval)
895 throws HttpInvalidAuthenticationException {
896 final TreeMap<String, String> treeMap = new TreeMap<String, String>();
897 final String argPath = getUri();
898 final ObjectNode arguri = getUriArgs();
899 if (arguri == null) {
900 throw new HttpInvalidAuthenticationException("Not enough argument");
901 }
902 final Iterator<Entry<String, JsonNode>> iterator = arguri.fields();
903 final DateTime dateTime = new DateTime();
904 DateTime received = null;
905 while (iterator.hasNext()) {
906 final Entry<String, JsonNode> entry = iterator.next();
907 final String key = entry.getKey();
908 if (key.equalsIgnoreCase(REST_ROOT_FIELD.ARG_X_AUTH_KEY.field)) {
909 continue;
910 }
911 final JsonNode values = entry.getValue();
912 if (key.equalsIgnoreCase(REST_ROOT_FIELD.ARG_X_AUTH_TIMESTAMP.field)) {
913 received = DateTime.parse(values.asText());
914 }
915 final String keylower = key.toLowerCase();
916 if (values != null) {
917 final String val;
918 if (values.isArray()) {
919 final JsonNode jsonNode = values.get(values.size() - 1);
920 val = jsonNode.asText();
921 } else {
922 val = values.asText();
923 }
924 treeMap.put(keylower, val);
925 }
926 }
927 if (received == null) {
928 final String date = getXAuthTimestamp();
929 received = DateTime.parse(date);
930 treeMap.put(REST_ROOT_FIELD.ARG_X_AUTH_TIMESTAMP.field.toLowerCase(),
931 date);
932 }
933 final String user = getXAuthUser();
934 if (ParametersChecker.isNotEmpty(user)) {
935 treeMap.put(REST_ROOT_FIELD.ARG_X_AUTH_USER.field.toLowerCase(), user);
936 }
937 if (maxInterval > 0 && received != null) {
938 final Duration duration = new Duration(received, dateTime);
939 if (Math.abs(duration.getMillis()) >= maxInterval) {
940 throw new HttpInvalidAuthenticationException(
941 "timestamp is not compatible with the maximum delay allowed");
942 }
943 } else if (maxInterval > 0) {
944 throw new HttpInvalidAuthenticationException(
945 "timestamp absent while required");
946 }
947 final String key = computeKey(hmacSha256, extraKey, treeMap, argPath);
948 if (!key.equalsIgnoreCase(getXAuthKey())) {
949 throw new HttpInvalidAuthenticationException(
950 "Invalid Authentication Key");
951 }
952
953 }
954
955
956
957
958
959
960
961
962
963 protected static String computeKey(final HmacSha256 hmacSha256,
964 final String extraKey,
965 final TreeMap<String, String> treeMap,
966 final String argPath)
967 throws HttpInvalidAuthenticationException {
968 final Set<String> keys = treeMap.keySet();
969 final StringBuilder builder = new StringBuilder(argPath);
970 if (!keys.isEmpty() || extraKey != null) {
971 builder.append('?');
972 }
973 boolean first = true;
974 for (final String keylower : keys) {
975 if (first) {
976 first = false;
977 } else {
978 builder.append('&');
979 }
980 builder.append(keylower).append('=').append(treeMap.get(keylower));
981 }
982 if (extraKey != null) {
983 if (!keys.isEmpty()) {
984 builder.append('&');
985 }
986 builder.append(REST_ROOT_FIELD.ARG_X_AUTH_INTERNALKEY.field).append('=')
987 .append(extraKey);
988 }
989 try {
990 return hmacSha256.cryptToHex(builder.toString());
991 } catch (final Exception e) {
992 throw new HttpInvalidAuthenticationException(e);
993 }
994 }
995
996 @Override
997 public String toString() {
998 return JsonHandler.writeAsString(arguments);
999 }
1000
1001 public final String prettyPrint() {
1002 return JsonHandler.prettyPrint(arguments);
1003 }
1004
1005 public static ObjectNode fillDetailedAllow(final METHOD method,
1006 final String path,
1007 final String command,
1008 final ObjectNode body,
1009 final JsonNode result) {
1010 final ObjectNode node = JsonHandler.createObjectNode();
1011 final ObjectNode node2 = node.putObject(method.name());
1012 node2.put(REST_FIELD.JSON_PATH.field, '/' + path);
1013 node2.put(REST_ROOT_FIELD.JSON_COMMAND.field, command);
1014 if (body != null) {
1015 node2.set(REST_FIELD.JSON_JSON.field, body);
1016 }
1017 if (result != null) {
1018 node2.set(REST_GROUP.ARGS_ANSWER.group, result);
1019 }
1020 return node;
1021 }
1022 }