|
22 | 22 | package org.apache.struts2.rest.handler;
|
23 | 23 |
|
24 | 24 | import com.opensymphony.xwork2.ActionInvocation;
|
| 25 | +import com.opensymphony.xwork2.ModelDriven; |
25 | 26 | import com.thoughtworks.xstream.XStream;
|
| 27 | +import com.thoughtworks.xstream.security.ArrayTypePermission; |
| 28 | +import com.thoughtworks.xstream.security.ExplicitTypePermission; |
| 29 | +import com.thoughtworks.xstream.security.NoTypePermission; |
| 30 | +import com.thoughtworks.xstream.security.NullPermission; |
| 31 | +import com.thoughtworks.xstream.security.PrimitiveTypePermission; |
| 32 | +import com.thoughtworks.xstream.security.TypePermission; |
| 33 | +import org.apache.logging.log4j.LogManager; |
| 34 | +import org.apache.logging.log4j.Logger; |
26 | 35 |
|
27 | 36 | import java.io.IOException;
|
28 | 37 | import java.io.Reader;
|
29 | 38 | import java.io.Writer;
|
| 39 | +import java.util.Collection; |
| 40 | +import java.util.Date; |
| 41 | +import java.util.Map; |
| 42 | +import java.util.Set; |
30 | 43 |
|
31 | 44 | /**
|
32 | 45 | * Handles XML content
|
33 | 46 | */
|
34 | 47 | public class XStreamHandler extends AbstractContentTypeHandler {
|
35 | 48 |
|
| 49 | + private static final Logger LOG = LogManager.getLogger(XStreamHandler.class); |
| 50 | + |
36 | 51 | public String fromObject(ActionInvocation invocation, Object obj, String resultCode, Writer out) throws IOException {
|
37 | 52 | if (obj != null) {
|
38 |
| - XStream xstream = createXStream(); |
| 53 | + XStream xstream = createXStream(invocation); |
39 | 54 | xstream.toXML(obj, out);
|
40 | 55 | }
|
41 | 56 | return null;
|
42 | 57 | }
|
43 | 58 |
|
44 | 59 | public void toObject(ActionInvocation invocation, Reader in, Object target) {
|
45 |
| - XStream xstream = createXStream(); |
| 60 | + XStream xstream = createXStream(invocation); |
46 | 61 | xstream.fromXML(in, target);
|
47 | 62 | }
|
48 |
| - |
| 63 | + |
| 64 | + /** |
| 65 | + * @deprecated use version with {@link ActionInvocation} |
| 66 | + */ |
| 67 | + @Deprecated |
49 | 68 | protected XStream createXStream() {
|
| 69 | + LOG.warn("You are using a deprecated API!"); |
50 | 70 | return new XStream();
|
51 | 71 | }
|
52 | 72 |
|
| 73 | + protected XStream createXStream(ActionInvocation invocation) { |
| 74 | + XStream stream = new XStream(); |
| 75 | + LOG.debug("Clears existing permissions"); |
| 76 | + stream.addPermission(NoTypePermission.NONE); |
| 77 | + |
| 78 | + LOG.debug("Adds per action permissions"); |
| 79 | + addPerActionPermission(invocation, stream); |
| 80 | + |
| 81 | + LOG.debug("Adds default permissions"); |
| 82 | + addDefaultPermissions(invocation, stream); |
| 83 | + return stream; |
| 84 | + } |
| 85 | + |
| 86 | + private void addPerActionPermission(ActionInvocation invocation, XStream stream) { |
| 87 | + Object action = invocation.getAction(); |
| 88 | + if (action instanceof AllowedClasses) { |
| 89 | + Set<Class<?>> allowedClasses = ((AllowedClasses) action).allowedClasses(); |
| 90 | + stream.addPermission(new ExplicitTypePermission(allowedClasses.toArray(new Class[allowedClasses.size()]))); |
| 91 | + } |
| 92 | + if (action instanceof AllowedClassNames) { |
| 93 | + Set<String> allowedClassNames = ((AllowedClassNames) action).allowedClassNames(); |
| 94 | + stream.addPermission(new ExplicitTypePermission(allowedClassNames.toArray(new String[allowedClassNames.size()]))); |
| 95 | + } |
| 96 | + if (action instanceof XStreamPermissionProvider) { |
| 97 | + Collection<TypePermission> permissions = ((XStreamPermissionProvider) action).getTypePermissions(); |
| 98 | + for (TypePermission permission : permissions) { |
| 99 | + stream.addPermission(permission); |
| 100 | + } |
| 101 | + } |
| 102 | + } |
| 103 | + |
| 104 | + protected void addDefaultPermissions(ActionInvocation invocation, XStream stream) { |
| 105 | + stream.addPermission(new ExplicitTypePermission(new Class[]{invocation.getAction().getClass()})); |
| 106 | + if (invocation.getAction() instanceof ModelDriven) { |
| 107 | + stream.addPermission(new ExplicitTypePermission(new Class[]{((ModelDriven) invocation.getAction()).getModel().getClass()})); |
| 108 | + } |
| 109 | + stream.addPermission(NullPermission.NULL); |
| 110 | + stream.addPermission(PrimitiveTypePermission.PRIMITIVES); |
| 111 | + stream.addPermission(ArrayTypePermission.ARRAYS); |
| 112 | + stream.addPermission(CollectionTypePermission.COLLECTIONS); |
| 113 | + stream.addPermission(new ExplicitTypePermission(new Class[]{Date.class})); |
| 114 | + } |
| 115 | + |
53 | 116 | public String getContentType() {
|
54 | 117 | return "application/xml";
|
55 | 118 | }
|
56 | 119 |
|
57 | 120 | public String getExtension() {
|
58 | 121 | return "xml";
|
59 | 122 | }
|
| 123 | + |
| 124 | + private static class CollectionTypePermission implements TypePermission { |
| 125 | + |
| 126 | + private static final TypePermission COLLECTIONS = new CollectionTypePermission(); |
| 127 | + |
| 128 | + @Override |
| 129 | + public boolean allows(Class type) { |
| 130 | + return type != null && type.isInterface() && |
| 131 | + (Collection.class.isAssignableFrom(type) || Map.class.isAssignableFrom(type)); |
| 132 | + } |
| 133 | + |
| 134 | + } |
60 | 135 | }
|
0 commit comments