Allow each request to define its own supported content types

This commit is contained in:
Paul Trudel 2024-04-22 16:11:10 -04:00
parent 9ec21acb2e
commit b6de2a1b55
21 changed files with 160 additions and 63 deletions

View File

@ -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 {

View File

@ -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<CreateMeeting.Params> {
public enum Params implements RequestParameters {
@ -51,8 +55,8 @@ public class CreateMeeting extends RequestWithChecksum<CreateMeeting.Params> {
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<CreateMeeting.Params> {
isBreakoutRoom = Boolean.parseBoolean(isBreakoutRoomString);
record = Boolean.parseBoolean(recordString);
}
@Override
public Set<String> getSupportedContentTypes() {
return Set.of(MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA, MediaType.APPLICATION_XML);
}
}

View File

@ -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<EndMeeting.Params> {
public enum Params implements RequestParameters {
@ -34,8 +34,8 @@ public class EndMeeting extends RequestWithChecksum<EndMeeting.Params> {
@Valid
private Password moderatorPassword;
public EndMeeting(Checksum checksum) {
super(checksum);
public EndMeeting(Checksum checksum, HttpServletRequest servletRequest) {
super(checksum, servletRequest);
moderatorPassword = new ModeratorPassword();
}

View File

@ -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<Enter.Params> {
@ContentTypeConstraint
public class Enter extends RequestWithSession<Enter.Params>{
public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken");
@ -27,7 +32,8 @@ public class Enter implements Request<Enter.Params> {
private SessionService sessionService;
public Enter() {
public Enter(HttpServletRequest servletRequest) {
super(servletRequest);
sessionService = new SessionService();
}

View File

@ -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<GetJoinUrl.Params> {
public class GetJoinUrl extends RequestWithSession<GetJoinUrl.Params> {
public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken");
@ -19,6 +20,10 @@ public class GetJoinUrl implements Request<GetJoinUrl.Params> {
@UserSessionConstraint
private String sessionToken;
public GetJoinUrl(HttpServletRequest servletRequest) {
super(servletRequest);
}
public String getSessionToken() {
return sessionToken;
}

View File

@ -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<GuestWait.Params> {
@ContentTypeConstraint
public class GuestWait extends RequestWithSession<GuestWait.Params>{
public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken");
@ -29,7 +32,8 @@ public class GuestWait implements Request<GuestWait.Params> {
private SessionService sessionService;
public GuestWait() {
public GuestWait(HttpServletRequest servletRequest) {
super(servletRequest);
sessionService = new SessionService();
}

View File

@ -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<InsertDocument.Params> {
public enum Params implements RequestParameters {
@ -21,8 +24,8 @@ public class InsertDocument extends RequestWithChecksum<InsertDocument.Params> {
@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<InsertDocument.Params> {
public void populateFromParamsMap(Map<String, String[]> params) {
if(params.containsKey(Params.MEETING_ID.getValue())) setMeetingID(params.get(Params.MEETING_ID.getValue())[0]);
}
@Override
public Set<String> getSupportedContentTypes() {
return Set.of(MediaType.APPLICATION_XML);
}
}

View File

@ -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<JoinMeeting.Params> {
public enum Params implements RequestParameters {
@ -57,8 +59,8 @@ public class JoinMeeting extends RequestWithChecksum<JoinMeeting.Params> {
@Valid
private Password joinPassword;
public JoinMeeting(Checksum checksum) {
super(checksum);
public JoinMeeting(Checksum checksum, HttpServletRequest servletRequest) {
super(checksum, servletRequest);
joinPassword = new JoinPassword();
}

View File

@ -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<LearningDashboard.Params> {
public class LearningDashboard extends RequestWithSession<LearningDashboard.Params> {
public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken");
@ -20,6 +21,10 @@ public class LearningDashboard implements Request<LearningDashboard.Params> {
@UserSessionConstraint
private String sessionToken;
public LearningDashboard(HttpServletRequest servletRequest) {
super(servletRequest);
}
public String getSessionToken() {
return sessionToken;
}

View File

@ -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<MeetingInfo.Params> {
public enum Params implements RequestParameters {
@ -22,8 +25,8 @@ public class MeetingInfo extends RequestWithChecksum<MeetingInfo.Params> {
@MeetingExistsConstraint
private String meetingID;
public MeetingInfo(Checksum checksum) {
super(checksum);
public MeetingInfo(Checksum checksum, HttpServletRequest servletRequest) {
super(checksum, servletRequest);
}
public String getMeetingID() {

View File

@ -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<MeetingRunning.Params> {
public enum Params implements RequestParameters {
@ -20,8 +23,8 @@ public class MeetingRunning extends RequestWithChecksum<MeetingRunning.Params> {
@MeetingIDConstraint
private String meetingID;
public MeetingRunning(Checksum checksum) {
super(checksum);
public MeetingRunning(Checksum checksum, HttpServletRequest servletRequest) {
super(checksum, servletRequest);
}
public String getMeetingID() {

View File

@ -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<P extends Enum<P> & RequestParameters> {
void populateFromParamsMap(Map<String, String[]> params);
void convertParamsFromString();
Set<String> getSupportedContentTypes();
HttpServletRequest getServletRequest();
}

View File

@ -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<P extends Enum<P> & RequestParameters> implements Request<P> {
@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<P extends Enum<P> & RequestParameters>
public void convertParamsFromString() {
}
@Override
public Set<String> getSupportedContentTypes() {
return Set.of(MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA);
}
@Override
public HttpServletRequest getServletRequest() {
return servletRequest;
}
}

View File

@ -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<P extends Enum<P> & RequestParameters> implements Request<P> {
protected HttpServletRequest servletRequest;
protected RequestWithSession(HttpServletRequest servletRequest) {
this.servletRequest = servletRequest;
}
@Override
public Set<String> getSupportedContentTypes() {
return Set.of(MediaType.APPLICATION_FORM_URLENCODED, MediaType.MULTIPART_FORM_DATA);
}
@Override
public HttpServletRequest getServletRequest() {
return servletRequest;
}
}

View File

@ -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<SignOut.Params> {
public class SignOut extends RequestWithSession<SignOut.Params> {
public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken");
@ -20,6 +21,10 @@ public class SignOut implements Request<SignOut.Params> {
@UserSessionConstraint
private String sessionToken;
public SignOut(HttpServletRequest servletRequest) {
super(servletRequest);
}
public String getSessionToken() {
return sessionToken;
}

View File

@ -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<SimpleRequest.Params> {
public enum Params implements RequestParameters {
@ -16,8 +19,8 @@ public class SimpleRequest extends RequestWithChecksum<SimpleRequest.Params> {
public String getValue() { return value; }
}
public SimpleRequest(Checksum checksum) {
super(checksum);
public SimpleRequest(Checksum checksum, HttpServletRequest servletRequest) {
super(checksum, servletRequest);
}
@Override

View File

@ -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<Stuns.Params> {
@ContentTypeConstraint
public class Stuns extends RequestWithSession<Stuns.Params> {
public enum Params implements RequestParameters {
SESSION_TOKEN("sessionToken");
@ -26,7 +28,10 @@ public class Stuns implements Request<Stuns.Params> {
private SessionService sessionService;
public Stuns() { sessionService = new SessionService(); }
public Stuns(HttpServletRequest servletRequest) {
super(servletRequest);
sessionService = new SessionService();
}
public String getSessionToken() {
return sessionToken;

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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<ContentTypeConstraint, HttpServletRequest> {
public class ContentTypeValidator implements ConstraintValidator<ContentTypeConstraint, Request> {
private static final Logger log = LoggerFactory.getLogger(ContentTypeValidator.class);
@ -25,17 +26,18 @@ public class ContentTypeValidator implements ConstraintValidator<ContentTypeCons
public void initialize(ContentTypeConstraint constraintAnnotation) {}
@Override
public boolean isValid(HttpServletRequest request, ConstraintValidatorContext context) {
String requestMethod = request.getMethod();
String contentType = request.getContentType();
String contentTypeHeader = request.getHeader("Content-Type");
public boolean isValid(Request request, ConstraintValidatorContext context) {
HttpServletRequest servletRequest = request.getServletRequest();
String requestMethod = servletRequest.getMethod();
String contentType = servletRequest.getContentType();
String contentTypeHeader = servletRequest.getHeader("Content-Type");
log.info("Validating {} request with content type {}", requestMethod, contentType);
boolean requestBodyPresent = request.getContentLength() > 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);
}
}

View File

@ -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;
}
}