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 }