diff --git a/bbb-common-web/build.sbt b/bbb-common-web/build.sbt index 308f51527d..60cb8fee69 100755 --- a/bbb-common-web/build.sbt +++ b/bbb-common-web/build.sbt @@ -112,5 +112,7 @@ libraryDependencies ++= Seq( "com.zaxxer" % "HikariCP" % "4.0.3", "commons-validator" % "commons-validator" % "1.7", "org.apache.tika" % "tika-core" % "2.8.0", - "org.apache.tika" % "tika-parsers-standard-package" % "2.8.0" + "org.apache.tika" % "tika-parsers-standard-package" % "2.8.0", + "org.scala-lang.modules" %% "scala-xml" % "2.2.0", + "jakarta.ws.rs" % "jakarta.ws.rs-api" % "3.1.0" ) diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/constraint/ContentTypeConstraint.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/constraint/ContentTypeConstraint.java new file mode 100644 index 0000000000..31d8ef7d1a --- /dev/null +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/constraint/ContentTypeConstraint.java @@ -0,0 +1,22 @@ +package org.bigbluebutton.api.model.constraint; + +import org.bigbluebutton.api.model.validator.ContentTypeValidator; + +import javax.validation.Constraint; +import javax.validation.Payload; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Constraint(validatedBy = ContentTypeValidator.class) +@Target(FIELD) +@Retention(RUNTIME) +public @interface ContentTypeConstraint { + + String key() default "contentTypeError"; + String message() default "Request content type is not supported"; + Class[] groups() default {}; + Class[] payload() default {}; +} diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/Checksum.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/Checksum.java index 23be59165e..2ceccd53ef 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/Checksum.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/Checksum.java @@ -1,5 +1,6 @@ package org.bigbluebutton.api.model.shared; +import org.bigbluebutton.api.model.constraint.ContentTypeConstraint; import org.bigbluebutton.api.model.constraint.NotEmpty; import org.bigbluebutton.api.util.ParamsUtil; @@ -15,6 +16,7 @@ public abstract class Checksum { protected String queryStringWithoutChecksum; + @ContentTypeConstraint protected HttpServletRequest request; public Checksum(String apiCall, String checksum, HttpServletRequest request) { diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/ContentTypeValidator.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/ContentTypeValidator.java new file mode 100644 index 0000000000..4983e232ce --- /dev/null +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/ContentTypeValidator.java @@ -0,0 +1,44 @@ +package org.bigbluebutton.api.model.validator; + +import jakarta.ws.rs.core.MediaType; +import org.apache.commons.compress.utils.Sets; +import org.bigbluebutton.api.model.constraint.ContentTypeConstraint; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.ConstraintValidator; +import javax.validation.ConstraintValidatorContext; +import java.util.Set; + +public class ContentTypeValidator implements ConstraintValidator { + + private static final Logger log = LoggerFactory.getLogger(ContentTypeValidator.class); + + private static final Set SUPPORTED_CONTENT_TYPES = Sets.newHashSet( + MediaType.APPLICATION_XML, + MediaType.APPLICATION_JSON, + MediaType.APPLICATION_FORM_URLENCODED, + MediaType.MULTIPART_FORM_DATA + ); + + @Override + public void initialize(ContentTypeConstraint constraintAnnotation) {} + + @Override + public boolean isValid(HttpServletRequest request, ConstraintValidatorContext context) { + String requestMethod = request.getMethod(); + String contentType = request.getContentType(); + log.info("Validating {} request with content type {}", requestMethod, contentType); + + boolean requestBodyPresent = request.getContentLength() > 0; + if (requestBodyPresent) { + if (contentType == null) return false; + else { + return SUPPORTED_CONTENT_TYPES.contains(contentType); + } + } + + return true; + } +} diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/GetChecksumValidator.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/GetChecksumValidator.java index 18e29c1dc8..352c54daca 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/GetChecksumValidator.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/GetChecksumValidator.java @@ -4,6 +4,7 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; +import jakarta.ws.rs.core.MediaType; import org.apache.commons.codec.digest.DigestUtils; import org.bigbluebutton.api.model.constraint.GetChecksumConstraint; import org.bigbluebutton.api.model.shared.GetChecksum; @@ -27,7 +28,12 @@ public class GetChecksumValidator implements ConstraintValidator 0; - if (queryStringPresent && requestBodyPresent) return false; + String contentType = request.getContentType(); + if (contentType != null) { + if (contentType.equalsIgnoreCase(MediaType.APPLICATION_FORM_URLENCODED) || contentType.equalsIgnoreCase(MediaType.MULTIPART_FORM_DATA)) { + if (queryStringPresent && requestBodyPresent) return false; + } + } if (securitySalt.isEmpty()) { log.warn("Security is disabled in this service. Make sure this is intentional."); diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy index 280e0b82d8..3989b37470 100755 --- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy +++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/controllers/ApiController.groovy @@ -110,7 +110,6 @@ class ApiController { log.info("attendeePW [${attendeePW}]") log.info("moderatorPW [${moderatorPW}]") - log.info("Content length type [${}]") if(attendeePW.equals("")) log.info("attendeePW is empty") if(moderatorPW.equals("")) log.info("moderatorPW is empty")