From 1e9e461f505ddbfd986240ccce688094c2b7fa6d Mon Sep 17 00:00:00 2001 From: Paul Date: Mon, 11 Mar 2024 19:05:58 +0000 Subject: [PATCH 01/16] Check for pressence of query and body --- .../api/model/shared/Checksum.java | 11 ++++- .../api/model/shared/GetChecksum.java | 5 +- .../api/model/shared/PostChecksum.java | 5 +- .../model/validator/GetChecksumValidator.java | 7 +++ .../api/service/ValidationService.java | 11 +++-- .../web/controllers/ApiController.groovy | 49 +++++++------------ 6 files changed, 48 insertions(+), 40 deletions(-) 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 bc7674a0af..23be59165e 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 @@ -3,6 +3,8 @@ package org.bigbluebutton.api.model.shared; import org.bigbluebutton.api.model.constraint.NotEmpty; import org.bigbluebutton.api.util.ParamsUtil; +import javax.servlet.http.HttpServletRequest; + public abstract class Checksum { @NotEmpty(message = "You must provide the API call", groups = ChecksumValidationGroup.class) @@ -13,9 +15,12 @@ public abstract class Checksum { protected String queryStringWithoutChecksum; - public Checksum(String apiCall, String checksum) { + protected HttpServletRequest request; + + public Checksum(String apiCall, String checksum, HttpServletRequest request) { this.apiCall = ParamsUtil.sanitizeString(apiCall); this.checksum = ParamsUtil.sanitizeString(checksum); + this.request = request; } public String getApiCall() { @@ -30,10 +35,14 @@ public abstract class Checksum { return checksum; } + public HttpServletRequest getRequest() { return request; } + public void setChecksum(String checksum) { this.checksum = checksum; } + public void setRequest(HttpServletRequest request) { this.request = request; } + public String getQueryStringWithoutChecksum() { return queryStringWithoutChecksum; } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java index 5c639fa1e8..c1df483052 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java @@ -3,6 +3,7 @@ package org.bigbluebutton.api.model.shared; import org.bigbluebutton.api.model.constraint.GetChecksumConstraint; import org.bigbluebutton.api.util.ParamsUtil; +import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.NotEmpty; @GetChecksumConstraint(groups = ChecksumValidationGroup.class) @@ -11,8 +12,8 @@ public class GetChecksum extends Checksum { @NotEmpty(message = "You must provide the query string") private String queryString; - public GetChecksum(String apiCall, String checksum, String queryString) { - super(apiCall, checksum); + public GetChecksum(String apiCall, String checksum, String queryString, HttpServletRequest request) { + super(apiCall, checksum, request); this.queryString = ParamsUtil.sanitizeString(queryString); removeChecksumFromQueryString(); } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/PostChecksum.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/PostChecksum.java index d5d72f3756..577c244e63 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/PostChecksum.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/PostChecksum.java @@ -3,6 +3,7 @@ package org.bigbluebutton.api.model.shared; import org.bigbluebutton.api.model.constraint.PostChecksumConstraint; import org.bigbluebutton.api.service.ValidationService; +import javax.servlet.http.HttpServletRequest; import java.util.Map; @PostChecksumConstraint(groups = ChecksumValidationGroup.class) @@ -10,8 +11,8 @@ public class PostChecksum extends Checksum { Map params; - public PostChecksum(String apiCall, String checksum, Map params) { - super(apiCall, checksum); + public PostChecksum(String apiCall, String checksum, Map params, HttpServletRequest request) { + super(apiCall, checksum, request); this.params = params; queryStringWithoutChecksum = ValidationService.buildQueryStringFromParamsMap(params); } 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 0e439c7263..18e29c1dc8 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 @@ -1,5 +1,6 @@ package org.bigbluebutton.api.model.validator; +import javax.servlet.http.HttpServletRequest; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; @@ -22,6 +23,12 @@ public class GetChecksumValidator implements ConstraintValidator 0; + + if (queryStringPresent && requestBodyPresent) return false; + if (securitySalt.isEmpty()) { log.warn("Security is disabled in this service. Make sure this is intentional."); return true; diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java index b26b367adb..070e7b6863 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java @@ -9,6 +9,7 @@ import org.bigbluebutton.api.util.ParamsUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.servlet.http.HttpServletRequest; import javax.validation.ConstraintViolation; import javax.validation.Validation; import javax.validation.Validator; @@ -70,11 +71,13 @@ public class ValidationService { validator = validatorFactory.getValidator(); } - public Map validate(ApiCall apiCall, Map params, String queryString) { + public Map validate(ApiCall apiCall, HttpServletRequest servletRequest) { + String queryString = servletRequest.getQueryString(); + Map params = servletRequest.getParameterMap(); log.info("Validating {} request with query string {}", apiCall.getName(), queryString); params = sanitizeParams(params); - Request request = initializeRequest(apiCall, params, queryString); + Request request = initializeRequest(apiCall, params, queryString, servletRequest); Map violations = new HashMap<>(); if(request == null) { @@ -101,7 +104,7 @@ public class ValidationService { } } - private Request initializeRequest(ApiCall apiCall, Map params, String queryString) { + private Request initializeRequest(ApiCall apiCall, Map params, String queryString, HttpServletRequest servletRequest) { Request request = null; Checksum checksum; @@ -116,7 +119,7 @@ public class ValidationService { switch(apiCall.requestType) { case GET: - checksum = new GetChecksum(apiCall.getName(), checksumValue, queryString); + checksum = new GetChecksum(apiCall.getName(), checksumValue, queryString, servletRequest); switch(apiCall) { case CREATE: request = new CreateMeeting(checksum); 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 8e49638816..280e0b82d8 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 @@ -45,6 +45,7 @@ import org.bigbluebutton.web.services.turn.StunServer import org.bigbluebutton.web.services.turn.RemoteIceCandidate import org.json.JSONArray import javax.servlet.ServletRequest +import javax.servlet.http.HttpServletRequest class ApiController { private static final String CONTROLLER_NAME = 'ApiController' @@ -109,14 +110,14 @@ 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") Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.CREATE, - request.getParameterMap(), - request.getQueryString() + request ) if(!(validationResponse == null)) { @@ -208,7 +209,6 @@ class ApiController { } } - /********************************************** * JOIN API *********************************************/ @@ -220,8 +220,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.JOIN, - request.getParameterMap(), - request.getQueryString() + request ) HashMap roles = new HashMap(); @@ -520,8 +519,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.MEETING_RUNNING, - request.getParameterMap(), - request.getQueryString() + request ) if(!(validationResponse == null)) { @@ -551,8 +549,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.END, - request.getParameterMap(), - request.getQueryString() + request ) if(!(validationResponse == null)) { @@ -595,8 +592,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.GET_MEETING_INFO, - request.getParameterMap(), - request.getQueryString() + request ) if(!(validationResponse == null)) { @@ -622,8 +618,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.GET_MEETINGS, - request.getParameterMap(), - request.getQueryString() + request ) if(!(validationResponse == null)) { @@ -660,8 +655,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.GET_SESSIONS, - request.getParameterMap(), - request.getQueryString() + request ) if(!(validationResponse == null)) { @@ -719,8 +713,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.GUEST_WAIT, - request.getParameterMap(), - request.getQueryString() + request ) if(!(validationResponse == null)) { msgKey = validationResponse.getKey() @@ -833,8 +826,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.ENTER, - request.getParameterMap(), - request.getQueryString(), + request ) if(!(validationResponse == null)) { respMessage = validationResponse.getValue() @@ -991,8 +983,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.STUNS, - request.getParameterMap(), - request.getQueryString(), + request ) if(!(validationResponse == null)) { @@ -1068,8 +1059,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.SIGN_OUT, - request.getParameterMap(), - request.getQueryString() + request ) if(validationResponse == null) { @@ -1113,8 +1103,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.INSERT_DOCUMENT, - request.getParameterMap(), - request.getQueryString() + request ) def externalMeetingId = params.meetingID.toString() @@ -1166,8 +1155,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.GET_JOIN_URL, - request.getParameterMap(), - request.getQueryString(), + request ) //Validate Session @@ -1266,8 +1254,7 @@ class ApiController { Map.Entry validationResponse = validateRequest( ValidationService.ApiCall.LEARNING_DASHBOARD, - request.getParameterMap(), - request.getQueryString(), + request ) //Validate Session @@ -1945,8 +1932,8 @@ class ApiController { redirect(url: newUri) } - private Map.Entry validateRequest(ValidationService.ApiCall apiCall, Map params, String queryString) { - Map violations = validationService.validate(apiCall, params, queryString) + private Map.Entry validateRequest(ValidationService.ApiCall apiCall, HttpServletRequest request) { + Map violations = validationService.validate(apiCall, request) Map.Entry response = null if(!violations.isEmpty()) { From 183983be7f3c66d4972987c91a8f352e9b46ab69 Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 12 Mar 2024 18:24:02 +0000 Subject: [PATCH 02/16] Added request content type validation --- bbb-common-web/build.sbt | 4 +- .../constraint/ContentTypeConstraint.java | 22 ++++++++++ .../api/model/shared/Checksum.java | 2 + .../model/validator/ContentTypeValidator.java | 44 +++++++++++++++++++ .../model/validator/GetChecksumValidator.java | 8 +++- .../web/controllers/ApiController.groovy | 1 - 6 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 bbb-common-web/src/main/java/org/bigbluebutton/api/model/constraint/ContentTypeConstraint.java create mode 100644 bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/ContentTypeValidator.java 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") From 8e40d918770203b4e41d23c5e6de4dc7a985c78d Mon Sep 17 00:00:00 2001 From: Paul Date: Wed, 13 Mar 2024 14:45:00 +0000 Subject: [PATCH 03/16] Removed support for application/json content --- .../bigbluebutton/api/model/validator/ContentTypeValidator.java | 1 - .../bigbluebutton/api/model/validator/GetChecksumValidator.java | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) 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 index 4983e232ce..e302c8d1b9 100644 --- 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 @@ -17,7 +17,6 @@ public class ContentTypeValidator implements ConstraintValidator SUPPORTED_CONTENT_TYPES = Sets.newHashSet( MediaType.APPLICATION_XML, - MediaType.APPLICATION_JSON, MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA ); 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 352c54daca..62638e4f77 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 @@ -29,6 +29,7 @@ public class GetChecksumValidator implements ConstraintValidator 0; String contentType = request.getContentType(); + log.info("Request content type: {}", contentType); if (contentType != null) { if (contentType.equalsIgnoreCase(MediaType.APPLICATION_FORM_URLENCODED) || contentType.equalsIgnoreCase(MediaType.MULTIPART_FORM_DATA)) { if (queryStringPresent && requestBodyPresent) return false; From e24e358dddfe569616d723c12d0ceca1f26e791c Mon Sep 17 00:00:00 2001 From: Paul Trudel Date: Thu, 18 Apr 2024 10:58:22 -0400 Subject: [PATCH 04/16] Reject requests with a body but no Content-Type header --- .../api/model/constraint/ContentTypeConstraint.java | 2 +- .../api/model/validator/ContentTypeValidator.java | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) 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 index 31d8ef7d1a..ff80a83a40 100644 --- 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 @@ -16,7 +16,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; public @interface ContentTypeConstraint { String key() default "contentTypeError"; - String message() default "Request content type is not supported"; + String message() default "Request content type is not supported or no Content-Type header was specified"; Class[] groups() default {}; Class[] payload() default {}; } 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 index e302c8d1b9..7992c12258 100644 --- 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 @@ -28,11 +28,12 @@ public class ContentTypeValidator implements ConstraintValidator 0; if (requestBodyPresent) { - if (contentType == null) return false; + if (contentType == null || contentTypeHeader == null) return false; else { return SUPPORTED_CONTENT_TYPES.contains(contentType); } From 1b481a9500afb5c47f93ca92b7b3c47d592f644c Mon Sep 17 00:00:00 2001 From: Paul Trudel Date: Thu, 18 Apr 2024 15:29:34 -0400 Subject: [PATCH 05/16] Changed content type validation error key and message --- .../api/model/constraint/ContentTypeConstraint.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index ff80a83a40..5eacf925c9 100644 --- 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 @@ -15,8 +15,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; @Retention(RUNTIME) public @interface ContentTypeConstraint { - String key() default "contentTypeError"; - String message() default "Request content type is not supported or no Content-Type header was specified"; + String key() default "unsupportedContentType"; + String message() default "POST request Content-Type is missing or unsupported"; Class[] groups() default {}; Class[] payload() default {}; } From de83c757162cab607d5dde84a3a9fd385712a05f Mon Sep 17 00:00:00 2001 From: Paul Trudel Date: Mon, 22 Apr 2024 16:11:10 -0400 Subject: [PATCH 06/16] Allow each request to define its own supported content types --- .../constraint/ContentTypeConstraint.java | 4 +-- .../api/model/request/CreateMeeting.java | 13 +++++++-- .../api/model/request/EndMeeting.java | 12 ++++---- .../api/model/request/Enter.java | 10 +++++-- .../api/model/request/GetJoinUrl.java | 7 ++++- .../api/model/request/GuestWait.java | 8 ++++-- .../api/model/request/InsertDocument.java | 14 ++++++++-- .../api/model/request/JoinMeeting.java | 6 ++-- .../api/model/request/LearningDashboard.java | 7 ++++- .../api/model/request/MeetingInfo.java | 7 +++-- .../api/model/request/MeetingRunning.java | 7 +++-- .../api/model/request/Request.java | 4 +++ .../model/request/RequestWithChecksum.java | 18 +++++++++++- .../api/model/request/RequestWithSession.java | 25 +++++++++++++++++ .../api/model/request/SignOut.java | 7 ++++- .../api/model/request/SimpleRequest.java | 7 +++-- .../api/model/request/Stuns.java | 9 ++++-- .../api/model/shared/Checksum.java | 10 +------ .../api/model/shared/GetChecksum.java | 4 +-- .../model/validator/ContentTypeValidator.java | 16 ++++++----- .../api/service/ValidationService.java | 28 +++++++++---------- 21 files changed, 160 insertions(+), 63 deletions(-) create mode 100644 bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/RequestWithSession.java 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 index 5eacf925c9..7baf6cfc42 100644 --- 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 @@ -7,11 +7,11 @@ 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.ElementType.TYPE; import static java.lang.annotation.RetentionPolicy.RUNTIME; @Constraint(validatedBy = ContentTypeValidator.class) -@Target(FIELD) +@Target(TYPE) @Retention(RUNTIME) public @interface ContentTypeConstraint { diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/CreateMeeting.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/CreateMeeting.java index fe027dc9c8..49a50c78d9 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/CreateMeeting.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/CreateMeeting.java @@ -1,12 +1,16 @@ package org.bigbluebutton.api.model.request; +import jakarta.ws.rs.core.MediaType; import org.bigbluebutton.api.model.constraint.*; import org.bigbluebutton.api.model.shared.Checksum; +import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.NotEmpty; import javax.validation.constraints.NotNull; import java.util.Map; +import java.util.Set; +@ContentTypeConstraint public class CreateMeeting extends RequestWithChecksum { public enum Params implements RequestParameters { @@ -51,8 +55,8 @@ public class CreateMeeting extends RequestWithChecksum { private String recordString; private Boolean record; - public CreateMeeting(Checksum checksum) { - super(checksum); + public CreateMeeting(Checksum checksum, HttpServletRequest servletRequest) { + super(checksum, servletRequest); } public String getName() { @@ -138,4 +142,9 @@ public class CreateMeeting extends RequestWithChecksum { isBreakoutRoom = Boolean.parseBoolean(isBreakoutRoomString); record = Boolean.parseBoolean(recordString); } + + @Override + public Set getSupportedContentTypes() { + return Set.of(MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA, MediaType.APPLICATION_XML); + } } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/EndMeeting.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/EndMeeting.java index 55feff00df..865dd363b0 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/EndMeeting.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/EndMeeting.java @@ -1,16 +1,16 @@ package org.bigbluebutton.api.model.request; -import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint; -import org.bigbluebutton.api.model.constraint.MeetingIDConstraint; -import org.bigbluebutton.api.model.constraint.NotEmpty; -import org.bigbluebutton.api.model.constraint.PasswordConstraint; +import org.bigbluebutton.api.model.constraint.*; import org.bigbluebutton.api.model.shared.Checksum; import org.bigbluebutton.api.model.shared.ModeratorPassword; import org.bigbluebutton.api.model.shared.Password; +import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.util.Map; +import java.util.Set; +@ContentTypeConstraint public class EndMeeting extends RequestWithChecksum { public enum Params implements RequestParameters { @@ -34,8 +34,8 @@ public class EndMeeting extends RequestWithChecksum { @Valid private Password moderatorPassword; - public EndMeeting(Checksum checksum) { - super(checksum); + public EndMeeting(Checksum checksum, HttpServletRequest servletRequest) { + super(checksum, servletRequest); moderatorPassword = new ModeratorPassword(); } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Enter.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Enter.java index 11981e1014..065cfb1803 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Enter.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Enter.java @@ -1,11 +1,16 @@ package org.bigbluebutton.api.model.request; +import jakarta.ws.rs.core.MediaType; import org.bigbluebutton.api.model.constraint.*; import org.bigbluebutton.api.service.SessionService; + +import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.NotNull; import java.util.Map; +import java.util.Set; -public class Enter implements Request { +@ContentTypeConstraint +public class Enter extends RequestWithSession{ public enum Params implements RequestParameters { SESSION_TOKEN("sessionToken"); @@ -27,7 +32,8 @@ public class Enter implements Request { private SessionService sessionService; - public Enter() { + public Enter(HttpServletRequest servletRequest) { + super(servletRequest); sessionService = new SessionService(); } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/GetJoinUrl.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/GetJoinUrl.java index 96a4120e42..8c30160b20 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/GetJoinUrl.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/GetJoinUrl.java @@ -2,9 +2,10 @@ package org.bigbluebutton.api.model.request; import org.bigbluebutton.api.model.constraint.UserSessionConstraint; +import javax.servlet.http.HttpServletRequest; import java.util.Map; -public class GetJoinUrl implements Request { +public class GetJoinUrl extends RequestWithSession { public enum Params implements RequestParameters { SESSION_TOKEN("sessionToken"); @@ -19,6 +20,10 @@ public class GetJoinUrl implements Request { @UserSessionConstraint private String sessionToken; + public GetJoinUrl(HttpServletRequest servletRequest) { + super(servletRequest); + } + public String getSessionToken() { return sessionToken; } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/GuestWait.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/GuestWait.java index 2e2e3aeecc..e882d9b1a3 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/GuestWait.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/GuestWait.java @@ -1,14 +1,17 @@ package org.bigbluebutton.api.model.request; +import org.bigbluebutton.api.model.constraint.ContentTypeConstraint; import org.bigbluebutton.api.model.constraint.MeetingEndedConstraint; import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint; import org.bigbluebutton.api.model.constraint.UserSessionConstraint; import org.bigbluebutton.api.service.SessionService; +import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.NotNull; import java.util.Map; -public class GuestWait implements Request { +@ContentTypeConstraint +public class GuestWait extends RequestWithSession{ public enum Params implements RequestParameters { SESSION_TOKEN("sessionToken"); @@ -29,7 +32,8 @@ public class GuestWait implements Request { private SessionService sessionService; - public GuestWait() { + public GuestWait(HttpServletRequest servletRequest) { + super(servletRequest); sessionService = new SessionService(); } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/InsertDocument.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/InsertDocument.java index 3d77fe8cbf..1b5a69a0d6 100644 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/InsertDocument.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/InsertDocument.java @@ -1,11 +1,14 @@ package org.bigbluebutton.api.model.request; +import jakarta.ws.rs.core.MediaType; import org.bigbluebutton.api.model.constraint.*; import org.bigbluebutton.api.model.shared.Checksum; +import javax.servlet.http.HttpServletRequest; import java.util.Map; +import java.util.Set; - +@ContentTypeConstraint public class InsertDocument extends RequestWithChecksum { public enum Params implements RequestParameters { @@ -21,8 +24,8 @@ public class InsertDocument extends RequestWithChecksum { @MeetingIDConstraint private String meetingID; - public InsertDocument(Checksum checksum) { - super(checksum); + public InsertDocument(Checksum checksum, HttpServletRequest servletRequest) { + super(checksum, servletRequest); } public String getMeetingID() { @@ -37,4 +40,9 @@ public class InsertDocument extends RequestWithChecksum { public void populateFromParamsMap(Map params) { if(params.containsKey(Params.MEETING_ID.getValue())) setMeetingID(params.get(Params.MEETING_ID.getValue())[0]); } + + @Override + public Set getSupportedContentTypes() { + return Set.of(MediaType.APPLICATION_XML); + } } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/JoinMeeting.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/JoinMeeting.java index b629d9c8bb..00c80b225a 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/JoinMeeting.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/JoinMeeting.java @@ -5,9 +5,11 @@ import org.bigbluebutton.api.model.shared.Checksum; import org.bigbluebutton.api.model.shared.JoinPassword; import org.bigbluebutton.api.model.shared.Password; +import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.util.Map; +@ContentTypeConstraint public class JoinMeeting extends RequestWithChecksum { public enum Params implements RequestParameters { @@ -57,8 +59,8 @@ public class JoinMeeting extends RequestWithChecksum { @Valid private Password joinPassword; - public JoinMeeting(Checksum checksum) { - super(checksum); + public JoinMeeting(Checksum checksum, HttpServletRequest servletRequest) { + super(checksum, servletRequest); joinPassword = new JoinPassword(); } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/LearningDashboard.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/LearningDashboard.java index a99556b373..263e729b67 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/LearningDashboard.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/LearningDashboard.java @@ -2,10 +2,11 @@ package org.bigbluebutton.api.model.request; import org.bigbluebutton.api.model.constraint.UserSessionConstraint; +import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.NotNull; import java.util.Map; -public class LearningDashboard implements Request { +public class LearningDashboard extends RequestWithSession { public enum Params implements RequestParameters { SESSION_TOKEN("sessionToken"); @@ -20,6 +21,10 @@ public class LearningDashboard implements Request { @UserSessionConstraint private String sessionToken; + public LearningDashboard(HttpServletRequest servletRequest) { + super(servletRequest); + } + public String getSessionToken() { return sessionToken; } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/MeetingInfo.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/MeetingInfo.java index b6f28fc1f4..c40052f7a0 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/MeetingInfo.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/MeetingInfo.java @@ -1,11 +1,14 @@ package org.bigbluebutton.api.model.request; +import org.bigbluebutton.api.model.constraint.ContentTypeConstraint; import org.bigbluebutton.api.model.constraint.MeetingExistsConstraint; import org.bigbluebutton.api.model.constraint.MeetingIDConstraint; import org.bigbluebutton.api.model.shared.Checksum; +import javax.servlet.http.HttpServletRequest; import java.util.Map; +@ContentTypeConstraint public class MeetingInfo extends RequestWithChecksum { public enum Params implements RequestParameters { @@ -22,8 +25,8 @@ public class MeetingInfo extends RequestWithChecksum { @MeetingExistsConstraint private String meetingID; - public MeetingInfo(Checksum checksum) { - super(checksum); + public MeetingInfo(Checksum checksum, HttpServletRequest servletRequest) { + super(checksum, servletRequest); } public String getMeetingID() { diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/MeetingRunning.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/MeetingRunning.java index 5f146cdcfb..8782714b0b 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/MeetingRunning.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/MeetingRunning.java @@ -1,10 +1,13 @@ package org.bigbluebutton.api.model.request; +import org.bigbluebutton.api.model.constraint.ContentTypeConstraint; import org.bigbluebutton.api.model.constraint.MeetingIDConstraint; import org.bigbluebutton.api.model.shared.Checksum; +import javax.servlet.http.HttpServletRequest; import java.util.Map; +@ContentTypeConstraint public class MeetingRunning extends RequestWithChecksum { public enum Params implements RequestParameters { @@ -20,8 +23,8 @@ public class MeetingRunning extends RequestWithChecksum { @MeetingIDConstraint private String meetingID; - public MeetingRunning(Checksum checksum) { - super(checksum); + public MeetingRunning(Checksum checksum, HttpServletRequest servletRequest) { + super(checksum, servletRequest); } public String getMeetingID() { diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Request.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Request.java index ed90a90ecb..9e3cd5c76e 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Request.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Request.java @@ -1,9 +1,13 @@ package org.bigbluebutton.api.model.request; +import javax.servlet.http.HttpServletRequest; import java.util.Map; +import java.util.Set; public interface Request

& RequestParameters> { void populateFromParamsMap(Map params); void convertParamsFromString(); + Set getSupportedContentTypes(); + HttpServletRequest getServletRequest(); } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/RequestWithChecksum.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/RequestWithChecksum.java index fa47bc7c0a..f86d656136 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/RequestWithChecksum.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/RequestWithChecksum.java @@ -1,17 +1,23 @@ package org.bigbluebutton.api.model.request; +import jakarta.ws.rs.core.MediaType; import org.bigbluebutton.api.model.shared.Checksum; +import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.util.Map; +import java.util.Set; public abstract class RequestWithChecksum

& RequestParameters> implements Request

{ @Valid protected Checksum checksum; - protected RequestWithChecksum(Checksum checksum) { + protected HttpServletRequest servletRequest; + + protected RequestWithChecksum(Checksum checksum, HttpServletRequest servletRequest) { this.checksum = checksum; + this.servletRequest = servletRequest; } public Checksum getChecksum() { @@ -27,4 +33,14 @@ public abstract class RequestWithChecksum

& RequestParameters> public void convertParamsFromString() { } + + @Override + public Set getSupportedContentTypes() { + return Set.of(MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA); + } + + @Override + public HttpServletRequest getServletRequest() { + return servletRequest; + } } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/RequestWithSession.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/RequestWithSession.java new file mode 100644 index 0000000000..7dc5c6445b --- /dev/null +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/RequestWithSession.java @@ -0,0 +1,25 @@ +package org.bigbluebutton.api.model.request; + +import jakarta.ws.rs.core.MediaType; + +import javax.servlet.http.HttpServletRequest; +import java.util.Set; + +public abstract class RequestWithSession

& RequestParameters> implements Request

{ + + protected HttpServletRequest servletRequest; + + protected RequestWithSession(HttpServletRequest servletRequest) { + this.servletRequest = servletRequest; + } + + @Override + public Set getSupportedContentTypes() { + return Set.of(MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA); + } + + @Override + public HttpServletRequest getServletRequest() { + return servletRequest; + } +} diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/SignOut.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/SignOut.java index 3a0ff66122..58e3994051 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/SignOut.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/SignOut.java @@ -2,10 +2,11 @@ package org.bigbluebutton.api.model.request; import org.bigbluebutton.api.model.constraint.UserSessionConstraint; +import javax.servlet.http.HttpServletRequest; import javax.validation.constraints.NotNull; import java.util.Map; -public class SignOut implements Request { +public class SignOut extends RequestWithSession { public enum Params implements RequestParameters { SESSION_TOKEN("sessionToken"); @@ -20,6 +21,10 @@ public class SignOut implements Request { @UserSessionConstraint private String sessionToken; + public SignOut(HttpServletRequest servletRequest) { + super(servletRequest); + } + public String getSessionToken() { return sessionToken; } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/SimpleRequest.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/SimpleRequest.java index 297dbdd6d4..a7ae3be80c 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/SimpleRequest.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/SimpleRequest.java @@ -1,9 +1,12 @@ package org.bigbluebutton.api.model.request; +import org.bigbluebutton.api.model.constraint.ContentTypeConstraint; import org.bigbluebutton.api.model.shared.Checksum; +import javax.servlet.http.HttpServletRequest; import java.util.Map; +@ContentTypeConstraint public class SimpleRequest extends RequestWithChecksum { public enum Params implements RequestParameters { @@ -16,8 +19,8 @@ public class SimpleRequest extends RequestWithChecksum { public String getValue() { return value; } } - public SimpleRequest(Checksum checksum) { - super(checksum); + public SimpleRequest(Checksum checksum, HttpServletRequest servletRequest) { + super(checksum, servletRequest); } @Override diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Stuns.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Stuns.java index 0050906634..423910729d 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Stuns.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/Stuns.java @@ -3,9 +3,11 @@ package org.bigbluebutton.api.model.request; import org.bigbluebutton.api.model.constraint.*; import org.bigbluebutton.api.service.SessionService; +import javax.servlet.http.HttpServletRequest; import java.util.Map; -public class Stuns implements Request { +@ContentTypeConstraint +public class Stuns extends RequestWithSession { public enum Params implements RequestParameters { SESSION_TOKEN("sessionToken"); @@ -26,7 +28,10 @@ public class Stuns implements Request { private SessionService sessionService; - public Stuns() { sessionService = new SessionService(); } + public Stuns(HttpServletRequest servletRequest) { + super(servletRequest); + sessionService = new SessionService(); + } public String getSessionToken() { return sessionToken; 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 2ceccd53ef..5ceb991c60 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 @@ -16,13 +16,9 @@ public abstract class Checksum { protected String queryStringWithoutChecksum; - @ContentTypeConstraint - protected HttpServletRequest request; - - public Checksum(String apiCall, String checksum, HttpServletRequest request) { + public Checksum(String apiCall, String checksum) { this.apiCall = ParamsUtil.sanitizeString(apiCall); this.checksum = ParamsUtil.sanitizeString(checksum); - this.request = request; } public String getApiCall() { @@ -37,14 +33,10 @@ public abstract class Checksum { return checksum; } - public HttpServletRequest getRequest() { return request; } - public void setChecksum(String checksum) { this.checksum = checksum; } - public void setRequest(HttpServletRequest request) { this.request = request; } - public String getQueryStringWithoutChecksum() { return queryStringWithoutChecksum; } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java index c1df483052..a99df6b1cb 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java @@ -12,8 +12,8 @@ public class GetChecksum extends Checksum { @NotEmpty(message = "You must provide the query string") private String queryString; - public GetChecksum(String apiCall, String checksum, String queryString, HttpServletRequest request) { - super(apiCall, checksum, request); + public GetChecksum(String apiCall, String checksum, String queryString) { + super(apiCall, checksum); this.queryString = ParamsUtil.sanitizeString(queryString); removeChecksumFromQueryString(); } 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 index 7992c12258..6ce868be88 100644 --- 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 @@ -3,6 +3,7 @@ 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.bigbluebutton.api.model.request.Request; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,7 +12,7 @@ import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.util.Set; -public class ContentTypeValidator implements ConstraintValidator { +public class ContentTypeValidator implements ConstraintValidator { private static final Logger log = LoggerFactory.getLogger(ContentTypeValidator.class); @@ -25,17 +26,18 @@ public class ContentTypeValidator implements ConstraintValidator 0; + boolean requestBodyPresent = servletRequest.getContentLength() > 0; if (requestBodyPresent) { if (contentType == null || contentTypeHeader == null) return false; else { - return SUPPORTED_CONTENT_TYPES.contains(contentType); + return request.getSupportedContentTypes().contains(contentType); } } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java index 070e7b6863..7882c6aaa4 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java @@ -119,47 +119,47 @@ public class ValidationService { switch(apiCall.requestType) { case GET: - checksum = new GetChecksum(apiCall.getName(), checksumValue, queryString, servletRequest); + checksum = new GetChecksum(apiCall.getName(), checksumValue, queryString); switch(apiCall) { case CREATE: - request = new CreateMeeting(checksum); + request = new CreateMeeting(checksum, servletRequest); break; case JOIN: - request = new JoinMeeting(checksum); + request = new JoinMeeting(checksum, servletRequest); break; case MEETING_RUNNING: - request = new MeetingRunning(checksum); + request = new MeetingRunning(checksum, servletRequest); break; case END: - request = new EndMeeting(checksum); + request = new EndMeeting(checksum, servletRequest); break; case GET_MEETING_INFO: - request = new MeetingInfo(checksum); + request = new MeetingInfo(checksum, servletRequest); break; case GET_MEETINGS: case GET_SESSIONS: - request = new SimpleRequest(checksum); + request = new SimpleRequest(checksum, servletRequest); break; case INSERT_DOCUMENT: - request = new InsertDocument(checksum); + request = new InsertDocument(checksum, servletRequest); break; case GUEST_WAIT: - request = new GuestWait(); + request = new GuestWait(servletRequest); break; case ENTER: - request = new Enter(); + request = new Enter(servletRequest); break; case STUNS: - request = new Stuns(); + request = new Stuns(servletRequest); break; case SIGN_OUT: - request = new SignOut(); + request = new SignOut(servletRequest); break; case LEARNING_DASHBOARD: - request = new LearningDashboard(); + request = new LearningDashboard(servletRequest); break; case GET_JOIN_URL: - request = new GetJoinUrl(); + request = new GetJoinUrl(servletRequest); break; } } From 7d156e882888f0e3281cd5acab663857767f9d77 Mon Sep 17 00:00:00 2001 From: Paul Trudel Date: Tue, 23 Apr 2024 11:44:57 -0400 Subject: [PATCH 07/16] Added servlet request back to the checksums --- .../bigbluebutton/api/model/shared/Checksum.java | 13 ++++++++++++- .../bigbluebutton/api/model/shared/GetChecksum.java | 4 ++-- .../api/service/ValidationService.java | 2 +- 3 files changed, 15 insertions(+), 4 deletions(-) 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 5ceb991c60..d6e9a231f4 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 @@ -16,9 +16,12 @@ public abstract class Checksum { protected String queryStringWithoutChecksum; - public Checksum(String apiCall, String checksum) { + protected HttpServletRequest request; + + public Checksum(String apiCall, String checksum, HttpServletRequest request) { this.apiCall = ParamsUtil.sanitizeString(apiCall); this.checksum = ParamsUtil.sanitizeString(checksum); + this.request = request; } public String getApiCall() { @@ -44,4 +47,12 @@ public abstract class Checksum { public void setQueryStringWithoutChecksum(String queryStringWithoutChecksum) { this.queryStringWithoutChecksum = queryStringWithoutChecksum; } + + public void setRequest(HttpServletRequest request) { + this.request = request; + } + + public HttpServletRequest getRequest() { + return request; + } } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java index a99df6b1cb..c1df483052 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java @@ -12,8 +12,8 @@ public class GetChecksum extends Checksum { @NotEmpty(message = "You must provide the query string") private String queryString; - public GetChecksum(String apiCall, String checksum, String queryString) { - super(apiCall, checksum); + public GetChecksum(String apiCall, String checksum, String queryString, HttpServletRequest request) { + super(apiCall, checksum, request); this.queryString = ParamsUtil.sanitizeString(queryString); removeChecksumFromQueryString(); } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java index 7882c6aaa4..481ea7b665 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java @@ -119,7 +119,7 @@ public class ValidationService { switch(apiCall.requestType) { case GET: - checksum = new GetChecksum(apiCall.getName(), checksumValue, queryString); + checksum = new GetChecksum(apiCall.getName(), checksumValue, queryString, servletRequest); switch(apiCall) { case CREATE: request = new CreateMeeting(checksum, servletRequest); From fa38c7747e0530554978ae2916ab30c88204bd57 Mon Sep 17 00:00:00 2001 From: Paul Trudel Date: Tue, 23 Apr 2024 12:23:24 -0400 Subject: [PATCH 08/16] Removed unused set of supported content types from validator --- .../api/model/validator/ContentTypeValidator.java | 6 ------ 1 file changed, 6 deletions(-) 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 index 6ce868be88..7c10477a1b 100644 --- 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 @@ -16,12 +16,6 @@ public class ContentTypeValidator implements ConstraintValidator SUPPORTED_CONTENT_TYPES = Sets.newHashSet( - MediaType.APPLICATION_XML, - MediaType.APPLICATION_FORM_URLENCODED, - MediaType.MULTIPART_FORM_DATA - ); - @Override public void initialize(ContentTypeConstraint constraintAnnotation) {} From fd6bd798f8e5f70fc165bf37a5d925823775ad56 Mon Sep 17 00:00:00 2001 From: Paul Trudel Date: Tue, 23 Apr 2024 14:40:15 -0400 Subject: [PATCH 09/16] Add support for text/xml to create and insertDocument --- .../java/org/bigbluebutton/api/model/request/CreateMeeting.java | 2 +- .../org/bigbluebutton/api/model/request/InsertDocument.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/CreateMeeting.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/CreateMeeting.java index 49a50c78d9..fbabaa3b53 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/CreateMeeting.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/CreateMeeting.java @@ -145,6 +145,6 @@ public class CreateMeeting extends RequestWithChecksum { @Override public Set getSupportedContentTypes() { - return Set.of(MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA, MediaType.APPLICATION_XML); + return Set.of(MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA, MediaType.APPLICATION_XML, MediaType.TEXT_XML); } } diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/InsertDocument.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/InsertDocument.java index 1b5a69a0d6..9d0d06ffd4 100644 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/InsertDocument.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/request/InsertDocument.java @@ -43,6 +43,6 @@ public class InsertDocument extends RequestWithChecksum { @Override public Set getSupportedContentTypes() { - return Set.of(MediaType.APPLICATION_XML); + return Set.of(MediaType.APPLICATION_XML, MediaType.TEXT_XML); } } From 698a736d58f3eb889b852e150e3ee2ea9b0a4ab8 Mon Sep 17 00:00:00 2001 From: Paul Trudel Date: Tue, 30 Apr 2024 08:44:07 -0400 Subject: [PATCH 10/16] Document API validation changes --- docs/docs/new-features.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/docs/new-features.md b/docs/docs/new-features.md index 415398b23f..d4634fa13e 100644 --- a/docs/docs/new-features.md +++ b/docs/docs/new-features.md @@ -196,6 +196,11 @@ If `preUploadedPresentationOverrideDefault=false` (or omitted, since `false` is In BigBlueButton 2.6.17/2.7.5 we added a new configuration property for bbb-apps-akka package under `services` called `checkSumAlgorithmForBreakouts`. By default the value is `"sha256"`. It controls the algorithm for checksum calculation for the breakout rooms join link. In case you overwrite bbb-web's `supportedChecksumAlgorithms` property removing sha256 you will need to set a supported algorithm here too. For example if you want to only use `sha512`, set `supportedChecksumAlgorithms=sha512` in `/etc/bigbluebutton/bbb-web.properties` and also set `checkSumAlgorithmForBreakouts="sha512"` in `/etc/bigbluebutton/bbb-apps-akka.conf` and then restart BigBlueButton. +#### Restrict supported content types on BBB API endpoints + +Breaking change: Requests that require both a URL query string and a request body (e.g. CREATE with pre-upload presentation or INSERTDOCUMENT) must provide a Content-Type header with a value of text/xml or application/xml. + +In BigBlueButton 2.6.19/2.7.7 we modified the request validation for the meeting related API endpoints such as CREATE, JOIN, GETMEETINGS, etc. These endpoints now support a limited set of content types that includes text/xml, application/xml, application/x-www-form-urlencoded, and multipart/form-data. By default each endpoint only supports application/x-www-form-urlencoded and multipart/form-data, but individual enpoints can override this and define their own set of supported content types. This is particularily relevant for the CREATE and INSERTDOCUMENT endpoints. The CREATE endpoint supports all of the four content types while INSERTDOCUMENT only supports text/xml and application/xml. Any requests with a content type that differs from the set supported by the target endpoint will be rejected with a new "unsupportedContentType" error. Additonally, any requests that contain both a URL query string AND a request body will be rejected with a checksum error. The exception to this is requests which have a content type of application/xml or text/xml. This is to allow CREATE with pre-upload presentation and INSERTDOCUMENT to continuing functioning as before. ### Development From b2b57aca0394ef9cc2088886a897704f4e374d8b Mon Sep 17 00:00:00 2001 From: Paul Trudel Date: Mon, 6 May 2024 17:56:59 +0000 Subject: [PATCH 11/16] Remove support for join POST requests and fix checksum calculation for POST requests --- .../bigbluebutton/api/model/shared/GetChecksum.java | 3 +-- .../api/model/validator/GetChecksumValidator.java | 12 ------------ .../bigbluebutton/api/service/ValidationService.java | 4 ---- .../org/bigbluebutton/web/UrlMappings.groovy | 4 ++++ 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java index c1df483052..952de208c9 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/GetChecksum.java @@ -8,8 +8,7 @@ import javax.validation.constraints.NotEmpty; @GetChecksumConstraint(groups = ChecksumValidationGroup.class) public class GetChecksum extends Checksum { - - @NotEmpty(message = "You must provide the query string") + private String queryString; public GetChecksum(String apiCall, String checksum, String queryString, HttpServletRequest request) { 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 62638e4f77..1395348ba0 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 @@ -24,18 +24,6 @@ public class GetChecksumValidator implements ConstraintValidator 0; - - String contentType = request.getContentType(); - log.info("Request content type: {}", contentType); - 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."); return true; diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java index 481ea7b665..bba230759e 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java @@ -113,10 +113,6 @@ public class ValidationService { checksumValue = params.get("checksum")[0]; } - if(queryString == null || queryString.isEmpty()) { - queryString = buildQueryStringFromParamsMap(params); - } - switch(apiCall.requestType) { case GET: checksum = new GetChecksum(apiCall.getName(), checksumValue, queryString, servletRequest); diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/UrlMappings.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/UrlMappings.groovy index 5390a8dae8..2a6aab198c 100755 --- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/UrlMappings.groovy +++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/UrlMappings.groovy @@ -63,6 +63,10 @@ class UrlMappings { action = [GET: 'downloadFile'] } + "/bigbluebutton/api/join"(controller: "api") { + action = [GET: 'join'] + } + "/bigbluebutton/api/getMeetings"(controller: "api") { action = [GET: 'getMeetingsHandler', POST: 'getMeetingsHandler'] } From 06b7628f61e1c51988ac9d01f41217dbb741dd04 Mon Sep 17 00:00:00 2001 From: Paul Trudel Date: Tue, 7 May 2024 20:34:20 +0000 Subject: [PATCH 12/16] Restrict supported HTTP method types on endpoints --- .../org/bigbluebutton/web/UrlMappings.groovy | 40 +++++++++++++++++++ .../web/controllers/ApiController.groovy | 3 +- 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/UrlMappings.groovy b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/UrlMappings.groovy index 2a6aab198c..ad8c713978 100755 --- a/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/UrlMappings.groovy +++ b/bigbluebutton-web/grails-app/controllers/org/bigbluebutton/web/UrlMappings.groovy @@ -63,10 +63,26 @@ class UrlMappings { action = [GET: 'downloadFile'] } + "/bigbluebutton/api/create"(controller: "api") { + action = [GET: 'create', POST: 'create'] + } + "/bigbluebutton/api/join"(controller: "api") { action = [GET: 'join'] } + "/bigbluebutton/api/isMeetingRunning"(controller: "api") { + action = [GET: 'isMeetingRunning', POST: 'isMeetingRunning'] + } + + "/bigbluebutton/api/end"(controller: "api") { + action = [GET: 'end', POST: 'end'] + } + + "/bigbluebutton/api/getMeetingInfo"(controller: "api") { + action = [GET: 'getMeetingInfo', POST: 'getMeetingInfo'] + } + "/bigbluebutton/api/getMeetings"(controller: "api") { action = [GET: 'getMeetingsHandler', POST: 'getMeetingsHandler'] } @@ -75,6 +91,30 @@ class UrlMappings { action = [GET: 'getSessionsHandler', POST: 'getSessionsHandler'] } + "/bigbluebutton/api/enter"(controller: "api") { + action = [GET: 'enter', POST: 'enter'] + } + + "/bigbluebutton/api/stuns"(controller: "api") { + action = [GET: 'stuns', POST: 'stuns'] + } + + "/bigbluebutton/api/signOut"(controller: "api") { + action = [GET: 'signOut', POST: 'signOut'] + } + + "/bigbluebutton/api/insertDocument"(controller: "api") { + action = [GET: 'insertDocument', POST: 'insertDocument'] + } + + "/bigbluebutton/api/getJoinUrl"(controller: "api") { + action = [GET: 'getJoinUrl', POST: 'getJoinUrl'] + } + + "/bigbluebutton/api/learningDashboard"(controller: "api") { + action = [GET: 'learningDashboard', POST: 'learningDashboard'] + } + "/bigbluebutton/api/getRecordings"(controller: "recording") { action = [GET: 'getRecordingsHandler', POST: 'getRecordingsHandler'] } 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 3989b37470..dc9b98bc57 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 @@ -599,7 +599,8 @@ class ApiController { return } - Meeting meeting = ServiceUtils.findMeetingFromMeetingID(params.meetingID); + String meetingId = params.list("meetingID")[0] + Meeting meeting = ServiceUtils.findMeetingFromMeetingID(meetingId); withFormat { xml { From 7a1081a974a9cec6a59dda46f1c13d8096e54966 Mon Sep 17 00:00:00 2001 From: Paul Trudel Date: Wed, 8 May 2024 13:40:46 +0000 Subject: [PATCH 13/16] Update docs to accurately document API functionality --- docs/docs/development/api.md | 30 ++++++++++++++++-------------- docs/docs/new-features.md | 6 ------ 2 files changed, 16 insertions(+), 20 deletions(-) diff --git a/docs/docs/development/api.md b/docs/docs/development/api.md index b797b15718..492c914424 100644 --- a/docs/docs/development/api.md +++ b/docs/docs/development/api.md @@ -106,7 +106,7 @@ Updated in 2.7: - **create** - **Added:** `preUploadedPresentation`, `preUploadedPresentationName`, `disabledFeatures` options`cameraAsContent`, `snapshotOfCurrentSlide`, `downloadPresentationOriginalFile`, `downloadPresentationConvertedToPdf`, `timer`, `learningDashboardDownloadSessionData` (2.7.5). -- **join** - **Added:** `redirectErrorUrl`, `userdata-bbb_fullaudio_bridge` +- **join** - **Added:** `redirectErrorUrl`, `userdata-bbb_fullaudio_bridge` and removed support for all HTTP request methods except GET ## API Data Types @@ -211,6 +211,8 @@ To use the security model, you must be able to create a SHA-1 checksum out of th You **MUST** send this checksum with **EVERY** API call. Since end users do not know your shared secret, they can not fake calls to the server, and they can not modify any API calls since changing a single parameter name or value by only one character will completely change the checksum required to validate the call. +**NOTE** Checksums for POST requests must be calculated using the URL query string as well. For example, if all request parameters are in the request body then the checksum will be calculated using an empty query string. + Implementations of the SHA-1 functionality exist in nearly all programming languages. Here are example methods or links to example implementations for various languages: - [JavaScript](http://pajhome.org.uk/crypt/md5/) @@ -280,7 +282,7 @@ The following response parameters are standard to every call and may be returned | message | Sometimes | String | A message that gives additional information about the status of the call. A message parameter will always be returned if the returncode was `FAILED`. A message may also be returned in some cases where returncode was `SUCCESS` if additional information would be helpful.| | messageKey | Sometimes | String | Provides similar functionality to the message and follows the same rules. However, a message key will be much shorter and will generally remain the same for the life of the API whereas a message may change over time. If your third party application would like to internationalize or otherwise change the standard messages returned, you can look up your own custom messages based on this messageKey.| -### create +### `GET` `POST` create Creates a BigBlueButton meeting. @@ -466,7 +468,7 @@ The receiving endpoint should respond with one of the following HTTP codes to in All other HTTP response codes will be treated as transient errors. -### join +### `GET` join Joins a user to the meeting specified in the meetingID parameter. @@ -503,7 +505,7 @@ There is a XML response for this call only when the `redirect` parameter is set ``` -### insertDocument +### `POST` insertDocument This endpoint insert one or more documents into a running meeting via API call @@ -555,7 +557,7 @@ curl -s -X POST "https://{your-host}/bigbluebutton/api/insertDocument?meetingID= There is also the possibility of passing the removable and downloadable variables inside the payload, they go in the `document` tag as already demonstrated. The way it works is exactly the same as in the [(POST) create endpoint](#pre-upload-slides) -### isMeetingRunning +### `GET` `POST` isMeetingRunning This call enables you to simply check on whether or not a meeting is running by looking it up with your meeting ID. @@ -584,7 +586,7 @@ http://yourserver.com/bigbluebutton/api/isMeetingRunning?meetingID=test01&ch running can be “true” or “false” that signals whether a meeting with this ID is currently running. -### end +### `GET` `POST` end Use this to forcibly end a meeting and kick all participants out of the meeting. @@ -628,7 +630,7 @@ curl --request POST \ **IMPORTANT NOTE:** You should note that when you call end meeting, it is simply sending a request to the backend (Red5) server that is handling all the conference traffic. That backend server will immediately attempt to send every connected client a logout event, kicking them from the meeting. It will then disconnect them, and the meeting will be ended. However, this may take several seconds, depending on network conditions. Therefore, the end meeting call will return a success as soon as the request is sent. But to be sure that it completed, you should then check back a few seconds later by using the `getMeetingInfo` or `isMeetingRunning` calls to verify that all participants have left the meeting and that it successfully ended. -### getMeetingInfo +### `GET` `POST` getMeetingInfo This call will return all of a meeting's information, including the list of attendees as well as start and end times. @@ -728,7 +730,7 @@ If a meeting is a breakout room itself, then `getMeetingInfo` will also return a ``` -### getMeetings +### `GET` `POST` getMeetings This call will return a list of all the meetings found on this server. @@ -781,7 +783,7 @@ http://yourserver.com/bigbluebutton/api/getMeetings?checksum=1234 ``` -### getRecordings +### `GET` getRecordings Retrieves the recordings that are available for playback for a given meetingID (or set of meeting IDs). Support for pagination was added in 2.6. @@ -896,7 +898,7 @@ Here the `getRecordings` API call returned back two recordings for the meetingID ``` -### publishRecordings +### `GET` publishRecordings Publish and unpublish recordings for a given recordID (or set of record IDs). @@ -924,7 +926,7 @@ Publish and unpublish recordings for a given recordID (or set of record IDs). ``` -### deleteRecordings +### `GET` deleteRecordings Delete one or more recordings for a given recordID (or set of record IDs). @@ -952,7 +954,7 @@ http://yourserver.com/bigbluebutton/api/deleteRecordings?[parameters]&checks ``` -### updateRecordings +### `GET` `POST` updateRecordings Update metadata for a given recordID (or set of record IDs). Available since version 1.1 @@ -979,7 +981,7 @@ Update metadata for a given recordID (or set of record IDs). Available since ver ``` -### getRecordingTextTracks +### `GET` `POST` getRecordingTextTracks Get a list of the caption/subtitle files currently available for a recording. It will include information about the captions (language, etc.), as well as a download link. This may be useful to retrieve live or automatically transcribed subtitles from a recording for manual editing. @@ -1059,7 +1061,7 @@ missingParameter noRecordings : No recording was found matching the provided recording ID. -### putRecordingTextTrack +### `POST` putRecordingTextTrack Upload a caption or subtitle file to add it to the recording. If there is any existing track with the same values for kind and lang, it will be replaced. diff --git a/docs/docs/new-features.md b/docs/docs/new-features.md index d4634fa13e..e7586ce462 100644 --- a/docs/docs/new-features.md +++ b/docs/docs/new-features.md @@ -196,12 +196,6 @@ If `preUploadedPresentationOverrideDefault=false` (or omitted, since `false` is In BigBlueButton 2.6.17/2.7.5 we added a new configuration property for bbb-apps-akka package under `services` called `checkSumAlgorithmForBreakouts`. By default the value is `"sha256"`. It controls the algorithm for checksum calculation for the breakout rooms join link. In case you overwrite bbb-web's `supportedChecksumAlgorithms` property removing sha256 you will need to set a supported algorithm here too. For example if you want to only use `sha512`, set `supportedChecksumAlgorithms=sha512` in `/etc/bigbluebutton/bbb-web.properties` and also set `checkSumAlgorithmForBreakouts="sha512"` in `/etc/bigbluebutton/bbb-apps-akka.conf` and then restart BigBlueButton. -#### Restrict supported content types on BBB API endpoints - -Breaking change: Requests that require both a URL query string and a request body (e.g. CREATE with pre-upload presentation or INSERTDOCUMENT) must provide a Content-Type header with a value of text/xml or application/xml. - -In BigBlueButton 2.6.19/2.7.7 we modified the request validation for the meeting related API endpoints such as CREATE, JOIN, GETMEETINGS, etc. These endpoints now support a limited set of content types that includes text/xml, application/xml, application/x-www-form-urlencoded, and multipart/form-data. By default each endpoint only supports application/x-www-form-urlencoded and multipart/form-data, but individual enpoints can override this and define their own set of supported content types. This is particularily relevant for the CREATE and INSERTDOCUMENT endpoints. The CREATE endpoint supports all of the four content types while INSERTDOCUMENT only supports text/xml and application/xml. Any requests with a content type that differs from the set supported by the target endpoint will be rejected with a new "unsupportedContentType" error. Additonally, any requests that contain both a URL query string AND a request body will be rejected with a checksum error. The exception to this is requests which have a content type of application/xml or text/xml. This is to allow CREATE with pre-upload presentation and INSERTDOCUMENT to continuing functioning as before. - ### Development For information on developing in BigBlueButton, see [setting up a development environment for 2.7](/development/guide). From e757cf15ee40a36414fb6b2b2de7b552fa94438d Mon Sep 17 00:00:00 2001 From: Paul Trudel Date: Wed, 8 May 2024 14:03:48 +0000 Subject: [PATCH 14/16] Removed unused POST checksum validation code --- .../constraint/PostChecksumConstraint.java | 22 ------- .../api/model/shared/PostChecksum.java | 23 ------- .../validator/PostChecksumValidator.java | 53 ---------------- .../api/service/ValidationService.java | 63 +++++-------------- 4 files changed, 17 insertions(+), 144 deletions(-) delete mode 100755 bbb-common-web/src/main/java/org/bigbluebutton/api/model/constraint/PostChecksumConstraint.java delete mode 100755 bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/PostChecksum.java delete mode 100755 bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/PostChecksumValidator.java diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/constraint/PostChecksumConstraint.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/constraint/PostChecksumConstraint.java deleted file mode 100755 index 4e359b8fed..0000000000 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/constraint/PostChecksumConstraint.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.bigbluebutton.api.model.constraint; - -import org.bigbluebutton.api.model.validator.PostChecksumValidator; - -import javax.validation.Constraint; -import javax.validation.Payload; -import java.lang.annotation.Retention; -import java.lang.annotation.Target; - -import static java.lang.annotation.ElementType.TYPE; -import static java.lang.annotation.RetentionPolicy.RUNTIME; - -@Constraint(validatedBy = PostChecksumValidator.class) -@Target(TYPE) -@Retention(RUNTIME) -public @interface PostChecksumConstraint { - - String key() default "checksumError"; - String message() default "Checksums do not match"; - Class[] groups() default {}; - Class[] payload() default {}; -} diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/PostChecksum.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/PostChecksum.java deleted file mode 100755 index 577c244e63..0000000000 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/shared/PostChecksum.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.bigbluebutton.api.model.shared; - -import org.bigbluebutton.api.model.constraint.PostChecksumConstraint; -import org.bigbluebutton.api.service.ValidationService; - -import javax.servlet.http.HttpServletRequest; -import java.util.Map; - -@PostChecksumConstraint(groups = ChecksumValidationGroup.class) -public class PostChecksum extends Checksum { - - Map params; - - public PostChecksum(String apiCall, String checksum, Map params, HttpServletRequest request) { - super(apiCall, checksum, request); - this.params = params; - queryStringWithoutChecksum = ValidationService.buildQueryStringFromParamsMap(params); - } - - public Map getParams() { return params; } - - public void setParams(Map params) { this.params = params; } -} diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/PostChecksumValidator.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/PostChecksumValidator.java deleted file mode 100755 index b34a178197..0000000000 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/model/validator/PostChecksumValidator.java +++ /dev/null @@ -1,53 +0,0 @@ -package org.bigbluebutton.api.model.validator; - -import org.apache.commons.codec.digest.DigestUtils; -import org.bigbluebutton.api.model.constraint.PostChecksumConstraint; -import org.bigbluebutton.api.model.shared.PostChecksum; -import org.bigbluebutton.api.service.ServiceUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import javax.validation.ConstraintValidator; -import javax.validation.ConstraintValidatorContext; - -public class PostChecksumValidator implements ConstraintValidator { - - private static Logger log = LoggerFactory.getLogger(PostChecksumValidator.class); - - @Override - public void initialize(PostChecksumConstraint constraintAnnotation) {} - - @Override - public boolean isValid(PostChecksum checksum, ConstraintValidatorContext context) { - String securitySalt = ServiceUtils.getValidationService().getSecuritySalt(); - - if (securitySalt.isEmpty()) { - log.warn("Security is disabled in this service. Make sure this is intentional."); - return true; - } - - String queryStringWithoutChecksum = checksum.getQueryStringWithoutChecksum(); - log.info("query string after checksum removed: [{}]", queryStringWithoutChecksum); - - if(queryStringWithoutChecksum == null) { - return false; - } - - String providedChecksum = checksum.getChecksum(); - log.info("CHECKSUM={} length={}", providedChecksum, providedChecksum.length()); - - if(providedChecksum == null) { - return false; - } - - String data = checksum.getApiCall() + queryStringWithoutChecksum + securitySalt; - String createdCheckSum = DigestUtils.sha1Hex(data); - - if (createdCheckSum == null || !createdCheckSum.equalsIgnoreCase(providedChecksum)) { - log.info("checksumError: failed checksum. our checksum: [{}], client: [{}]", createdCheckSum, providedChecksum); - return false; - } - - return true; - } -} diff --git a/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java b/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java index bba230759e..8c241d40eb 100755 --- a/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java +++ b/bbb-common-web/src/main/java/org/bigbluebutton/api/service/ValidationService.java @@ -4,7 +4,6 @@ import org.bigbluebutton.api.model.request.*; import org.bigbluebutton.api.model.shared.Checksum; import org.bigbluebutton.api.model.shared.ChecksumValidationGroup; import org.bigbluebutton.api.model.shared.GetChecksum; -import org.bigbluebutton.api.model.shared.PostChecksum; import org.bigbluebutton.api.util.ParamsUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -113,51 +112,23 @@ public class ValidationService { checksumValue = params.get("checksum")[0]; } - switch(apiCall.requestType) { - case GET: - checksum = new GetChecksum(apiCall.getName(), checksumValue, queryString, servletRequest); - switch(apiCall) { - case CREATE: - request = new CreateMeeting(checksum, servletRequest); - break; - case JOIN: - request = new JoinMeeting(checksum, servletRequest); - break; - case MEETING_RUNNING: - request = new MeetingRunning(checksum, servletRequest); - break; - case END: - request = new EndMeeting(checksum, servletRequest); - break; - case GET_MEETING_INFO: - request = new MeetingInfo(checksum, servletRequest); - break; - case GET_MEETINGS: - case GET_SESSIONS: - request = new SimpleRequest(checksum, servletRequest); - break; - case INSERT_DOCUMENT: - request = new InsertDocument(checksum, servletRequest); - break; - case GUEST_WAIT: - request = new GuestWait(servletRequest); - break; - case ENTER: - request = new Enter(servletRequest); - break; - case STUNS: - request = new Stuns(servletRequest); - break; - case SIGN_OUT: - request = new SignOut(servletRequest); - break; - case LEARNING_DASHBOARD: - request = new LearningDashboard(servletRequest); - break; - case GET_JOIN_URL: - request = new GetJoinUrl(servletRequest); - break; - } + if (Objects.requireNonNull(apiCall.requestType) == RequestType.GET) { + checksum = new GetChecksum(apiCall.getName(), checksumValue, queryString, servletRequest); + request = switch (apiCall) { + case CREATE -> new CreateMeeting(checksum, servletRequest); + case JOIN -> new JoinMeeting(checksum, servletRequest); + case MEETING_RUNNING -> new MeetingRunning(checksum, servletRequest); + case END -> new EndMeeting(checksum, servletRequest); + case GET_MEETING_INFO -> new MeetingInfo(checksum, servletRequest); + case GET_MEETINGS, GET_SESSIONS -> new SimpleRequest(checksum, servletRequest); + case INSERT_DOCUMENT -> new InsertDocument(checksum, servletRequest); + case GUEST_WAIT -> new GuestWait(servletRequest); + case ENTER -> new Enter(servletRequest); + case STUNS -> new Stuns(servletRequest); + case SIGN_OUT -> new SignOut(servletRequest); + case LEARNING_DASHBOARD -> new LearningDashboard(servletRequest); + case GET_JOIN_URL -> new GetJoinUrl(servletRequest); + }; } return request; From 122b70603542356ee0ed6481d4a24c51a424b9a5 Mon Sep 17 00:00:00 2001 From: Paul Trudel Date: Wed, 8 May 2024 18:37:43 +0000 Subject: [PATCH 15/16] Readd documentation of API changes to New Features section --- docs/docs/new-features.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/docs/new-features.md b/docs/docs/new-features.md index e7586ce462..af9dd6b961 100644 --- a/docs/docs/new-features.md +++ b/docs/docs/new-features.md @@ -196,6 +196,10 @@ If `preUploadedPresentationOverrideDefault=false` (or omitted, since `false` is In BigBlueButton 2.6.17/2.7.5 we added a new configuration property for bbb-apps-akka package under `services` called `checkSumAlgorithmForBreakouts`. By default the value is `"sha256"`. It controls the algorithm for checksum calculation for the breakout rooms join link. In case you overwrite bbb-web's `supportedChecksumAlgorithms` property removing sha256 you will need to set a supported algorithm here too. For example if you want to only use `sha512`, set `supportedChecksumAlgorithms=sha512` in `/etc/bigbluebutton/bbb-web.properties` and also set `checkSumAlgorithmForBreakouts="sha512"` in `/etc/bigbluebutton/bbb-apps-akka.conf` and then restart BigBlueButton. +#### Removed support for POST requests on `join` endpoint and Content-Type headers are now required + +In BigBlueButton 2.6.19/2.7.7 POST requests are no longer allowed for the `join` endpoint. To ensure they are validated properly, a `Content-Type` header must also be provided for POST requests that contain data in the request body. Endpoints now support a limited set of content types that includes `text/xml`, `application/xml`, `application/x-www-form-url-encoded`, and `multipart/form-data`. By default each endpoint only supports `application/x-www-form-urlencoded` and `multipart/form-data`, but individual endpoints can override this and define their own set of supported content types. The `create` endpoint supports all of the four previously listed content types while `insertDocument` supports only `text/xml` and `application/xml`. Any requests with a content type that differs from the set supported by the target endpoint will be rejected with a new `unsupportedContentType` error. + ### Development For information on developing in BigBlueButton, see [setting up a development environment for 2.7](/development/guide). From 62eb2c53cf465a1a1bd4721528c86b49a0a450fa Mon Sep 17 00:00:00 2001 From: Anton Georgiev Date: Wed, 15 May 2024 10:36:05 -0400 Subject: [PATCH 16/16] Update docs/docs/new-features.md --- docs/docs/new-features.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/new-features.md b/docs/docs/new-features.md index af9dd6b961..cff86b07e7 100644 --- a/docs/docs/new-features.md +++ b/docs/docs/new-features.md @@ -198,7 +198,7 @@ In BigBlueButton 2.6.17/2.7.5 we added a new configuration property for bbb-apps #### Removed support for POST requests on `join` endpoint and Content-Type headers are now required -In BigBlueButton 2.6.19/2.7.7 POST requests are no longer allowed for the `join` endpoint. To ensure they are validated properly, a `Content-Type` header must also be provided for POST requests that contain data in the request body. Endpoints now support a limited set of content types that includes `text/xml`, `application/xml`, `application/x-www-form-url-encoded`, and `multipart/form-data`. By default each endpoint only supports `application/x-www-form-urlencoded` and `multipart/form-data`, but individual endpoints can override this and define their own set of supported content types. The `create` endpoint supports all of the four previously listed content types while `insertDocument` supports only `text/xml` and `application/xml`. Any requests with a content type that differs from the set supported by the target endpoint will be rejected with a new `unsupportedContentType` error. +In BigBlueButton 2.6.18/2.7.8 POST requests are no longer allowed for the `join` endpoint. To ensure they are validated properly, a `Content-Type` header must also be provided for POST requests that contain data in the request body. Endpoints now support a limited set of content types that includes `text/xml`, `application/xml`, `application/x-www-form-url-encoded`, and `multipart/form-data`. By default each endpoint only supports `application/x-www-form-urlencoded` and `multipart/form-data`, but individual endpoints can override this and define their own set of supported content types. The `create` endpoint supports all of the four previously listed content types while `insertDocument` supports only `text/xml` and `application/xml`. Any requests with a content type that differs from the set supported by the target endpoint will be rejected with a new `unsupportedContentType` error. ### Development