From 6fca66f5b1c355ed897c328d11a9b7d08c31d7b2 Mon Sep 17 00:00:00 2001 From: Bryce Willey Date: Wed, 9 Sep 2026 14:22:39 -0400 Subject: [PATCH] Refactoring UserCreds A ton of stuff assumed that all calls would have a TylerToken, even after delegating the actual search for it to the AuthenticateRequestInterceptor. Needed to make interfaces for the actual credentials, and then let everything handle if there's not credentials available. Tyler implementations should return / return ASAP, but TrueFiling implementations should work fine without creds. Started some simple Exception handling stuff to let Tyler implementations throw errors more cleanly, without it needing to be present in the services. --- .../litlab/efsp/server/EfspServer.java | 10 +- .../AuthenticateRequestInterceptor.java | 35 ++++--- .../{utils => auth}/EfspSecurityContext.java | 23 ++++- .../efsp/server/auth/LoginInterface.java | 16 ++- .../{utils => auth}/NeedsAuthorization.java | 2 +- .../efsp/server/auth/NullUserCreds.java | 15 +++ .../litlab/efsp/server/auth/SecurityHub.java | 57 +++++++---- .../efsp/server/auth/TrueFilingLogin.java | 37 +++++++ .../litlab/efsp/server/auth/TylerLogin.java | 16 ++- .../efsp/server/auth/TylerUserFromServer.java | 11 +++ .../litlab/efsp/server/auth/UserCreds.java | 15 +++ .../auth/UserNamePassword.java} | 42 ++++---- .../server/services/AdminUserService.java | 73 +++++++------- .../services/ApiUserSettingsService.java | 4 +- .../services/AuthenticationService.java | 16 +-- .../efsp/server/services/CasesService.java | 46 +++++---- .../services/CourtSchedulingService.java | 35 +++---- .../server/services/FilingReviewService.java | 99 +++++++------------ .../FirmAttorneyAndServiceService.java | 64 ++++++------ .../services/JurisdictionServiceHandle.java | 16 +++ .../services/MessageSettingsService.java | 4 +- .../efsp/server/services/PaymentsService.java | 61 ++++++------ .../services/api/EfmFilingInterface.java | 32 +++--- .../efsp/server/services/impl/Ecf4Filer.java | 78 +++++++-------- .../impl/EfmCheckableFilingInterface.java | 17 ++-- .../server/utils/ProxyServerException.java | 6 ++ .../utils/ProxyServerExceptionMapper.java | 21 ++++ .../efsp/server/utils/ServiceHelpers.java | 26 ++--- .../server/utils/TylerUserFromServer.java | 12 --- .../efsp/tyler/ecfcodes/TylerCodeUpdater.java | 4 +- .../efsp/server/auth/SecurityHubTest.java | 7 +- .../server/services/AdminUserServiceTest.java | 4 +- .../server/services/CodesServiceTest.java | 2 +- 33 files changed, 521 insertions(+), 385 deletions(-) rename proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/{utils => auth}/AuthenticateRequestInterceptor.java (73%) rename proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/{utils => auth}/EfspSecurityContext.java (67%) rename proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/{utils => auth}/NeedsAuthorization.java (90%) create mode 100644 proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/NullUserCreds.java create mode 100644 proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/TrueFilingLogin.java create mode 100644 proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/TylerUserFromServer.java create mode 100644 proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/UserCreds.java rename proxyserver/src/main/java/edu/suffolk/litlab/efsp/{tyler/TylerUserNamePassword.java => server/auth/UserNamePassword.java} (59%) create mode 100644 proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/ProxyServerException.java create mode 100644 proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/ProxyServerExceptionMapper.java delete mode 100644 proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/TylerUserFromServer.java diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/EfspServer.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/EfspServer.java index 988b34c55..2586e7a4f 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/EfspServer.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/EfspServer.java @@ -14,6 +14,7 @@ import edu.suffolk.litlab.efsp.db.MessageSettingsDatabase; import edu.suffolk.litlab.efsp.db.UserDatabase; import edu.suffolk.litlab.efsp.docassemble.DocassembleToFilingInformationConverter; +import edu.suffolk.litlab.efsp.server.auth.AuthenticateRequestInterceptor; import edu.suffolk.litlab.efsp.server.auth.SecurityHub; import edu.suffolk.litlab.efsp.server.services.ApiUserSettingsService; import edu.suffolk.litlab.efsp.server.services.AuthenticationService; @@ -25,12 +26,12 @@ import edu.suffolk.litlab.efsp.server.setup.EfmRestCallbackInterface; import edu.suffolk.litlab.efsp.server.setup.truefiling.TrueFilingModuleSetup; import edu.suffolk.litlab.efsp.server.setup.tyler.TylerModuleSetup; -import edu.suffolk.litlab.efsp.server.utils.AuthenticateRequestInterceptor; import edu.suffolk.litlab.efsp.server.utils.EnumExceptionMapper; import edu.suffolk.litlab.efsp.server.utils.JsonExceptionMapper; import edu.suffolk.litlab.efsp.server.utils.ObservabilityHeadersInterceptor; import edu.suffolk.litlab.efsp.server.utils.ObservabilityResetInterceptor; import edu.suffolk.litlab.efsp.server.utils.OrgMessageSender; +import edu.suffolk.litlab.efsp.server.utils.ProxyServerExceptionMapper; import edu.suffolk.litlab.efsp.server.utils.SendMessage; import edu.suffolk.litlab.efsp.server.utils.ServiceHelpers; import edu.suffolk.litlab.efsp.server.utils.SoapExceptionMapper; @@ -136,7 +137,7 @@ protected EfspServer( Map.of( "xml", MediaType.APPLICATION_XML, "json", MediaType.APPLICATION_JSON)); - sf.setProviders(providers(ldSupplier)); + sf.setProviders(providers(ldSupplier, security)); sf.setAddress(ServiceHelpers.BASE_LOCAL_URL); server = sf.create(); @@ -196,7 +197,7 @@ private static void setupDatabases(DataSource codeDs, DataSource userDs) } } - public static List providers(Supplier ldSupplier) { + public static List providers(Supplier ldSupplier, SecurityHub security) { var objMapper = new ObjectMapper().registerModule(new Jdk8Module()); return List.of( new JAXBElementProvider(), @@ -204,9 +205,10 @@ public static List providers(Supplier ldSupplier) { new SoapExceptionMapper(), new JsonExceptionMapper(), new EnumExceptionMapper(), + new ProxyServerExceptionMapper(), new ObservabilityHeadersInterceptor(), new ObservabilityResetInterceptor(), - new AuthenticateRequestInterceptor(ldSupplier)); + new AuthenticateRequestInterceptor(ldSupplier, security)); } public static void main(String[] args) throws Exception { diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/AuthenticateRequestInterceptor.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/AuthenticateRequestInterceptor.java similarity index 73% rename from proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/AuthenticateRequestInterceptor.java rename to proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/AuthenticateRequestInterceptor.java index 960af1257..eaf648bf0 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/AuthenticateRequestInterceptor.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/AuthenticateRequestInterceptor.java @@ -1,11 +1,10 @@ -package edu.suffolk.litlab.efsp.server.utils; +package edu.suffolk.litlab.efsp.server.auth; import edu.suffolk.litlab.efsp.Jurisdiction; import edu.suffolk.litlab.efsp.db.LoginDatabase; import edu.suffolk.litlab.efsp.db.model.AtRest; -import edu.suffolk.litlab.efsp.server.auth.TylerLogin; import edu.suffolk.litlab.efsp.server.logging.MDCWrappers; -import edu.suffolk.litlab.efsp.tyler.TylerUserNamePassword; +import edu.suffolk.litlab.efsp.stdlib.NonEmptyString; import edu.suffolk.litlab.efsp.utils.Hasher; import jakarta.annotation.Priority; import jakarta.ws.rs.Priorities; @@ -30,9 +29,12 @@ public class AuthenticateRequestInterceptor implements ContainerRequestFilter { private static final Logger log = LoggerFactory.getLogger(AuthenticateRequestInterceptor.class); public static final String API_KEY_HEADER = "X-API-KEY"; private final Supplier ldSupplier; + private final SecurityHub securityHub; - public AuthenticateRequestInterceptor(Supplier ldSupplier) { + public AuthenticateRequestInterceptor( + Supplier ldSupplier, SecurityHub securityHub) { this.ldSupplier = ldSupplier; + this.securityHub = securityHub; } @Override @@ -45,11 +47,19 @@ public void filter(ContainerRequestContext requestContext) throws IOException { requestContext.abortWith(Response.status(401).build()); return; } - var maybeJurisdiction = + Optional maybeJurisdiction = getJurisdiction(requestContext.getUriInfo().getAbsolutePath().getPath()); - var maybeCreds = maybeJurisdiction.flatMap(j -> getCreds(requestContext, j)); + var maybeCreds = + maybeJurisdiction.flatMap( + j -> getCreds(securityHub.getTokenHeaderValue(requestContext.getHeaders(), j))); var p = maybeCreds.map(creds -> new TylerUserFromServer(creds)); - var security = new EfspSecurityContext(p, atRest.get(), ""); + Optional userId = + maybeJurisdiction.flatMap( + j -> { + var headerVal = securityHub.getUserIdHeaderValue(requestContext.getHeaders(), j); + return NonEmptyString.create(headerVal); + }); + var security = new EfspSecurityContext(p, userId, atRest.get(), ""); requestContext.setSecurityContext(security); } catch (SQLException ex) { log.error("SQL when trying to check API Key / login:", ex); @@ -81,15 +91,12 @@ public static Optional getJurisdiction(String path) { *

Based on what the current path of the request is (it needs to be under "jurisdictions/..." * to get the right login token). */ - public static Optional getCreds( - ContainerRequestContext requestContext, Jurisdiction jurisdiction) { - String tylerToken = - requestContext.getHeaderString(TylerLogin.getHeaderKeyFromJurisdiction(jurisdiction)); - var maybeCreds = TylerUserNamePassword.userCredsFromAuthorization(tylerToken); + public static Optional getCreds(String token) { + var maybeCreds = UserNamePassword.userCredsFromAuthorization(token); if (maybeCreds.isPresent()) { - MDC.put(MDCWrappers.USER_ID, Hasher.makeHash(tylerToken)); + MDC.put(MDCWrappers.USER_ID, Hasher.makeHash(token)); } else { - if (tylerToken != null && !tylerToken.isBlank()) { + if (token != null && !token.isBlank()) { MDC.put(MDCWrappers.USER_ID, "(invalid token)"); } } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/EfspSecurityContext.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/EfspSecurityContext.java similarity index 67% rename from proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/EfspSecurityContext.java rename to proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/EfspSecurityContext.java index cbb6e5d89..b05e15c4d 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/EfspSecurityContext.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/EfspSecurityContext.java @@ -1,6 +1,8 @@ -package edu.suffolk.litlab.efsp.server.utils; +package edu.suffolk.litlab.efsp.server.auth; import edu.suffolk.litlab.efsp.db.model.AtRest; +import edu.suffolk.litlab.efsp.stdlib.NonEmptyString; +import jakarta.annotation.Nullable; import jakarta.ws.rs.core.SecurityContext; import java.security.Principal; import java.util.Optional; @@ -9,12 +11,17 @@ public class EfspSecurityContext implements SecurityContext { private final Optional principal; + @Nullable private final Optional userIdFromHeader; private final AtRest serverInfo; private final String role; // TODO: make this the Tyler role? idk how to do that every query public EfspSecurityContext( - Optional principal, AtRest serverInfo, String role) { + Optional principal, + Optional userIdFromHeader, + AtRest serverInfo, + String role) { this.principal = principal; + this.userIdFromHeader = userIdFromHeader; this.serverInfo = serverInfo; this.role = role; } @@ -28,6 +35,18 @@ public Optional getTylerUser() { return principal; } + public UserCreds getUserCreds() { + if (principal.isPresent()) { + return principal.get().creds(); + } else { + return new NullUserCreds(); + } + } + + public Optional getUserId() { + return userIdFromHeader; + } + public UUID getServerId() { return serverInfo.serverId; } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/LoginInterface.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/LoginInterface.java index d3031b1fb..f4223ba04 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/LoginInterface.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/LoginInterface.java @@ -1,13 +1,27 @@ package edu.suffolk.litlab.efsp.server.auth; import com.fasterxml.jackson.databind.JsonNode; +import jakarta.ws.rs.core.MultivaluedMap; import java.util.Optional; public interface LoginInterface { + /** If LoginResult is present, login succeeded. */ Optional login(JsonNode loginInfo); String getLoginName(); - String getHeaderKey(); + /** + * Gets the required login token for all subsequent calls. + * + * @return might be null + */ + String getTokenHeaderValue(MultivaluedMap headers); + + /** + * Gets the user ID of the user initiating these calls. + * + * @return might be null + */ + String getUserIdHeaderValue(MultivaluedMap headers); } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/NeedsAuthorization.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/NeedsAuthorization.java similarity index 90% rename from proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/NeedsAuthorization.java rename to proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/NeedsAuthorization.java index 76ce7bee5..8ecb6b24b 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/NeedsAuthorization.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/NeedsAuthorization.java @@ -1,4 +1,4 @@ -package edu.suffolk.litlab.efsp.server.utils; +package edu.suffolk.litlab.efsp.server.auth; import static java.lang.annotation.ElementType.METHOD; import static java.lang.annotation.ElementType.TYPE; diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/NullUserCreds.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/NullUserCreds.java new file mode 100644 index 000000000..3f093336f --- /dev/null +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/NullUserCreds.java @@ -0,0 +1,15 @@ +package edu.suffolk.litlab.efsp.server.auth; + +import java.util.List; +import org.apache.cxf.headers.Header; + +public class NullUserCreds implements UserCreds { + + public String getUserName() { + return ""; + } + + public List

toHeaders() { + return List.of(); + } +} diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/SecurityHub.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/SecurityHub.java index 261fd5699..336a290fe 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/SecurityHub.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/SecurityHub.java @@ -5,14 +5,13 @@ import edu.suffolk.litlab.efsp.db.LoginDatabase; import edu.suffolk.litlab.efsp.db.model.AtRest; import edu.suffolk.litlab.efsp.db.model.NewTokens; +import jakarta.ws.rs.core.MultivaluedMap; import java.sql.SQLException; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.function.Function; import java.util.function.Supplier; -import java.util.stream.Collectors; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,8 +29,8 @@ public class SecurityHub { private static final Logger log = LoggerFactory.getLogger(SecurityHub.class); - private final List tylerLoginObjs; - private final Map>> loginFunctions; + private final Map loginByKey; + private final Map loginByJurisdiction; private final Supplier ldSupplier; /** @@ -41,21 +40,33 @@ public class SecurityHub { */ public SecurityHub(Supplier ldSupplier, List jurisdictions) { this.ldSupplier = ldSupplier; - if (jurisdictions.isEmpty()) { - this.tylerLoginObjs = List.of(); - } else { - this.tylerLoginObjs = - jurisdictions.stream().map(j -> new TylerLogin(j)).collect(Collectors.toList()); + this.loginByKey = new HashMap<>(); + this.loginByJurisdiction = new HashMap<>(); + for (var jurisdiction : jurisdictions) { + var login = + switch (jurisdiction.getVendor()) { + case Jurisdiction.Vendor.TYLER -> new TylerLogin(jurisdiction); + case Jurisdiction.Vendor.TRUE_FILING -> new TrueFilingLogin(jurisdiction); + }; + this.loginByKey.put(login.getLoginName(), login); + this.loginByJurisdiction.put(jurisdiction, login); } + } - this.loginFunctions = new HashMap<>(); - this.loginFunctions.put( - "jeffnet", - info -> - Optional.of(new LoginResult(Map.of("JEFFNET-TOKEN", "deprecated"), Optional.empty()))); - this.loginFunctions.putAll( - this.tylerLoginObjs.stream() - .collect(Collectors.toMap(lo -> lo.getLoginName(), lo -> (info) -> lo.login(info)))); + public String getUserIdHeaderValue( + MultivaluedMap headers, Jurisdiction jurisdiction) { + if (!this.loginByJurisdiction.containsKey(jurisdiction)) { + return null; + } + return this.loginByJurisdiction.get(jurisdiction).getUserIdHeaderValue(headers); + } + + public String getTokenHeaderValue( + MultivaluedMap headers, Jurisdiction jurisdiction) { + if (!this.loginByJurisdiction.containsKey(jurisdiction)) { + return null; + } + return this.loginByJurisdiction.get(jurisdiction).getTokenHeaderValue(headers); } /** @@ -99,11 +110,15 @@ public Optional login(String apiKey, JsonNode loginInfo) { if (orgName.equalsIgnoreCase("api_key")) { continue; } + if (orgName.equalsIgnoreCase("jeffnet")) { + // Backwards compatible + newTokens.put("JEFFNET-TOKEN", "deprecated"); + continue; + } // TODO(brycew): feels hacky, but we don't want an additional column to the db for each new // jurisdiction - if (!loginFunctions.containsKey(orgName)) { - log.error( - "There is no {} to login to: loginFunctions: {}", orgName, loginFunctions.keySet()); + if (!loginByKey.containsKey(orgName)) { + log.error("There is no {} to login to: loginFunctions: {}", orgName, loginByKey.keySet()); return Optional.empty(); } @@ -115,7 +130,7 @@ public Optional login(String apiKey, JsonNode loginInfo) { log.error("There is no {} to login to: enabled map: {}", permissionsName, atRest.enabled); return Optional.empty(); } - Optional maybeResult = loginFunctions.get(orgName).apply(loginInfo.get(orgName)); + Optional maybeResult = loginByKey.get(orgName).login(loginInfo.get(orgName)); if (maybeResult.isEmpty()) { log.warn("Couldn't login to {}", orgName); return Optional.empty(); diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/TrueFilingLogin.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/TrueFilingLogin.java new file mode 100644 index 000000000..73c8e1a30 --- /dev/null +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/TrueFilingLogin.java @@ -0,0 +1,37 @@ +package edu.suffolk.litlab.efsp.server.auth; + +import com.fasterxml.jackson.databind.JsonNode; +import edu.suffolk.litlab.efsp.Jurisdiction; +import jakarta.ws.rs.core.MultivaluedMap; +import java.util.Map; +import java.util.Optional; + +public class TrueFilingLogin implements LoginInterface { + + private final Jurisdiction jurisdiction; + + public TrueFilingLogin(Jurisdiction jurisdiction) { + this.jurisdiction = jurisdiction; + } + + @Override + public Optional login(JsonNode loginInfo) { + // TrueFiling doesn't have a user account system, so nothing to do! + return Optional.of(new LoginResult(Map.of(), Optional.empty())); + } + + @Override + public String getLoginName() { + return "truefiling-" + jurisdiction.getName(); + } + + @Override + public String getTokenHeaderValue(MultivaluedMap headers) { + return null; + } + + @Override + public String getUserIdHeaderValue(MultivaluedMap headers) { + return null; + } +} diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/TylerLogin.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/TylerLogin.java index a5aa958c9..ce6ae116e 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/TylerLogin.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/TylerLogin.java @@ -6,6 +6,7 @@ import edu.suffolk.litlab.efsp.tyler.TylerClients; import edu.suffolk.litlab.efsp.tyler.TylerUserClient; import edu.suffolk.litlab.efsp.tyler.TylerUserFactory; +import jakarta.ws.rs.core.MultivaluedMap; import java.util.Map; import java.util.Optional; import org.slf4j.Logger; @@ -80,8 +81,8 @@ public Optional login(JsonNode loginInfo) { } @Override - public String getHeaderKey() { - return getHeaderKeyFromJurisdiction(this.jurisdiction); + public String getTokenHeaderValue(MultivaluedMap headers) { + return headers.getFirst(getHeaderKey()); } @Override @@ -89,7 +90,16 @@ public String getLoginName() { return "tyler-" + this.jurisdiction.getName(); } - public static String getHeaderId(Jurisdiction jurisdiction) { + @Override + public String getUserIdHeaderValue(MultivaluedMap headers) { + return headers.getFirst(getHeaderId(this.jurisdiction)); + } + + private String getHeaderKey() { + return getHeaderKeyFromJurisdiction(this.jurisdiction); + } + + private static String getHeaderId(Jurisdiction jurisdiction) { return "TYLER-ID-" + jurisdiction.getName().toUpperCase(); } } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/TylerUserFromServer.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/TylerUserFromServer.java new file mode 100644 index 000000000..74b6069fa --- /dev/null +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/TylerUserFromServer.java @@ -0,0 +1,11 @@ +package edu.suffolk.litlab.efsp.server.auth; + +import java.security.Principal; + +public record TylerUserFromServer(UserCreds creds) implements Principal { + // Principals can only have one name, so stick with the user name (email). + @Override + public String getName() { + return creds.getUserName(); + } +} diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/UserCreds.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/UserCreds.java new file mode 100644 index 000000000..a888b643c --- /dev/null +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/UserCreds.java @@ -0,0 +1,15 @@ +package edu.suffolk.litlab.efsp.server.auth; + +import java.util.List; +import org.apache.cxf.headers.Header; + +public interface UserCreds { + + /** The user's identifiable name (in Tyler this is an email). */ + String getUserName(); + + /** + * @return the user's credentials in the form of a SOAP header. + */ + List
toHeaders(); +} diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/TylerUserNamePassword.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/UserNamePassword.java similarity index 59% rename from proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/TylerUserNamePassword.java rename to proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/UserNamePassword.java index ff6c272f8..bb9a7b02f 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/TylerUserNamePassword.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/auth/UserNamePassword.java @@ -1,9 +1,8 @@ -package edu.suffolk.litlab.efsp.tyler; +package edu.suffolk.litlab.efsp.server.auth; import jakarta.xml.bind.JAXBException; import jakarta.xml.bind.annotation.XmlElement; import jakarta.xml.bind.annotation.XmlRootElement; -import java.util.Arrays; import java.util.List; import java.util.Optional; import javax.xml.namespace.QName; @@ -11,23 +10,28 @@ import org.apache.cxf.jaxb.JAXBDataBinding; import tyler.efm.latest.services.schema.authenticateresponse.AuthenticateResponseType; +/** + * A class that handles authentication to an external server by simply accepting a user's username + * and password, separated by a colon in a header. + * + *

Only Tyler is silly enough to do this though, so practically this is just theirs. + */ @XmlRootElement(name = "UserNameHeader") -public class TylerUserNamePassword { +public class UserNamePassword implements UserCreds { @XmlElement(name = "UserName") private String userName; @XmlElement(name = "Password") private String password; - public TylerUserNamePassword() {} + public UserNamePassword() {} - public TylerUserNamePassword(String userName, String password) { + public UserNamePassword(String userName, String password) { this.userName = userName; this.password = password; } - public static Optional userCredsFromAuthorization( - String userColonPassword) { + public static Optional userCredsFromAuthorization(String userColonPassword) { if (userColonPassword == null) { return Optional.empty(); } @@ -36,19 +40,21 @@ public static Optional userCredsFromAuthorization( } String email = userColonPassword.split(":")[0]; String password = userColonPassword.split(":")[1]; - return Optional.of(new TylerUserNamePassword(email, password)); + return Optional.of(new UserNamePassword(email, password)); } public String getUserName() { return userName; } - public Header toHeader() { + @Override + public List

toHeaders() { try { - return new Header( - new QName("urn:tyler:efm:services", "UserNameHeader"), - this, - new JAXBDataBinding(TylerUserNamePassword.class)); + return List.of( + new Header( + new QName("urn:tyler:efm:services", "UserNameHeader"), + this, + new JAXBDataBinding(UserNamePassword.class))); } catch (JAXBException ex) { // We are always passing this class to JAXB. If at any point it would fail, // it should be a compile time thing tbh. We don't need the extra overhead @@ -60,15 +66,11 @@ public Header toHeader() { /** * Convenience method to make the Tyler specific SOAP Header. * - * @param userName the email of the user that is sending this request - * @param passwordHash the auth token (gotten from the AuthenticateUser call). + * @param AuthenticateResponseType authRes the response from the server if the user is + * authenticated. * @return the Header object to the request context's Header.HEADER_LIST */ - public static Header makeHeader(String userName, String passwordHash) { - return (new TylerUserNamePassword(userName, passwordHash)).toHeader(); - } - public static List
makeHeaderList(AuthenticateResponseType authRes) { - return Arrays.asList(makeHeader(authRes.getEmail(), authRes.getPasswordHash())); + return (new UserNamePassword(authRes.getEmail(), authRes.getPasswordHash())).toHeaders(); } } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/AdminUserService.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/AdminUserService.java index d0abcecba..0db47f326 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/AdminUserService.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/AdminUserService.java @@ -9,13 +9,14 @@ import com.webcohesion.enunciate.metadata.rs.ResponseCode; import com.webcohesion.enunciate.metadata.rs.StatusCodes; import edu.suffolk.litlab.efsp.Jurisdiction; -import edu.suffolk.litlab.efsp.server.auth.TylerLogin; +import edu.suffolk.litlab.efsp.server.auth.EfspSecurityContext; +import edu.suffolk.litlab.efsp.server.auth.NeedsAuthorization; +import edu.suffolk.litlab.efsp.server.auth.NullUserCreds; +import edu.suffolk.litlab.efsp.server.auth.UserCreds; import edu.suffolk.litlab.efsp.server.logging.MDCWrappers; -import edu.suffolk.litlab.efsp.server.utils.EfspSecurityContext; import edu.suffolk.litlab.efsp.server.utils.EndpointReflection; -import edu.suffolk.litlab.efsp.server.utils.NeedsAuthorization; import edu.suffolk.litlab.efsp.server.utils.ServiceHelpers; -import edu.suffolk.litlab.efsp.server.utils.TylerUserFromServer; +import edu.suffolk.litlab.efsp.stdlib.NonEmptyString; import edu.suffolk.litlab.efsp.tyler.TylerClients; import edu.suffolk.litlab.efsp.tyler.TylerErrorCodes; import edu.suffolk.litlab.efsp.tyler.TylerFirmClient; @@ -162,12 +163,13 @@ public Response getAll() { @NeedsAuthorization public Response getSelfUser(@Context SecurityContext security, @Context HttpHeaders httpHeaders) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.getSelfUser"); - Optional port = setupUserPort(((EfspSecurityContext) security)); + var efspSecurity = (EfspSecurityContext) security; + Optional port = setupUserPort(efspSecurity); if (port.isEmpty()) { return Response.status(401).build(); } - String userId = httpHeaders.getHeaderString(TylerLogin.getHeaderId(jurisdiction)); - if (userId == null || userId.isBlank()) { + var userId = efspSecurity.getUserId(); + if (userId.isEmpty()) { return Response.status(500) .entity( "Server does not have a Tyler UUID for the current account. Can you give it to me?") @@ -175,7 +177,7 @@ public Response getSelfUser(@Context SecurityContext security, @Context HttpHead } GetUserRequestType req = new GetUserRequestType(); - req.setUserID(userId); + req.setUserID(userId.get().get()); GetUserResponseType resp = port.get().getUser(req); return makeResponse(resp, () -> Response.ok(resp.getUser()).build()); } @@ -222,7 +224,7 @@ public Response updateNotificationPrefs( public Response selfResendActivationEmail( @Context SecurityContext security, String emailToSendTo) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.selfResendActivationEmail"); - Optional port = setupUserPort(Optional.empty(), false); + Optional port = setupUserPort(new NullUserCreds(), false); if (port.isEmpty()) { return Response.status(401).build(); } @@ -240,7 +242,7 @@ public Response resendActivationEmail( @Context SecurityContext security, @PathParam("id") String id) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.resendActivationEmail"); Optional port = - setupFirmPort(firmFactory, ((EfspSecurityContext) security).getTylerUser()); + setupFirmPort(firmFactory, ((EfspSecurityContext) security).getUserCreds()); if (port.isEmpty()) { return Response.status(401).build(); } @@ -282,7 +284,7 @@ public Response resetPassword( @Context SecurityContext security, @PathParam("id") String id, ResetPasswordParams params) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.resetPassword"); Optional port = - setupFirmPort(firmFactory, ((EfspSecurityContext) security).getTylerUser()); + setupFirmPort(firmFactory, ((EfspSecurityContext) security).getUserCreds()); if (port.isEmpty()) { return Response.status(401).build(); } @@ -333,7 +335,7 @@ public Response setPassword(@Context SecurityContext security, SetPasswordParams @NeedsAuthorization public Response selfResetPassword(String emailToSend) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.selfResetPassword"); - Optional port = setupUserPort(Optional.empty(), false); + Optional port = setupUserPort(new NullUserCreds(), false); if (port.isEmpty()) { return Response.status(401).build(); } @@ -361,20 +363,19 @@ public Response getUser( @PathParam("id") String id) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.getUser"); EfspSecurityContext efspSecurity = (EfspSecurityContext) security; - String tylerId = - httpHeaders.getHeaderString(TylerLogin.getHeaderKeyFromJurisdiction(jurisdiction)); + Optional userId = efspSecurity.getUserId(); GetUserRequestType getUserReq = new GetUserRequestType(); getUserReq.setUserID(id); Function userGetter = null; - if (tylerId != null && !tylerId.isBlank() && tylerId.equals(id)) { + if (userId.map(s -> s.get().equals(id)).orElse(false)) { Optional userPort = setupUserPort(efspSecurity); if (userPort.isEmpty()) { return Response.status(401).build(); } userGetter = (req) -> userPort.get().getUser(getUserReq); } else { - Optional port = setupFirmPort(firmFactory, efspSecurity.getTylerUser()); + Optional port = setupFirmPort(firmFactory, efspSecurity.getUserCreds()); if (port.isEmpty()) { return Response.status(401).build(); } @@ -393,7 +394,7 @@ public Response getUserList( @QueryParam("page_size") @DefaultValue("20") int pageSize) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.getUserList"); Optional port = - setupFirmPort(firmFactory, ((EfspSecurityContext) security).getTylerUser()); + setupFirmPort(firmFactory, ((EfspSecurityContext) security).getUserCreds()); if (port.isEmpty()) { return Response.status(401).build(); } @@ -411,17 +412,19 @@ public Response getUserList( @PATCH @Path("/user") @NeedsAuthorization - public Response updateUser( - @Context SecurityContext security, @Context HttpHeaders httpHeaders, UserType updatedUser) { + public Response updateUser(@Context SecurityContext security, UserType updatedUser) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.updateUser"); - Optional port = - setupUserPort(((EfspSecurityContext) security).getTylerUser(), true); + var efspSecurity = (EfspSecurityContext) security; + Optional port = setupUserPort(efspSecurity.getUserCreds(), true); if (port.isEmpty()) { return Response.status(401).build(); } + if (efspSecurity.getUserId().isEmpty()) { + return Response.status(401).build(); + } // Ensure the user exists already. GetUserRequestType getUserReq = new GetUserRequestType(); - getUserReq.setUserID(httpHeaders.getHeaderString(TylerLogin.getHeaderId(jurisdiction))); + getUserReq.setUserID(efspSecurity.getUserId().map(s -> s.get()).orElse("")); GetUserResponseType userRes = port.get().getUser(getUserReq); if (TylerErrorCodes.checkErrors(userRes.getError()).isPresent()) { return Response.status(401, userRes.getError().getErrorText()).build(); @@ -450,7 +453,7 @@ public Response updateUserById( @Context SecurityContext security, @PathParam("id") String id, UserType updatedUser) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.updateUserById"); Optional port = - setupFirmPort(firmFactory, ((EfspSecurityContext) security).getTylerUser()); + setupFirmPort(firmFactory, ((EfspSecurityContext) security).getUserCreds()); if (port.isEmpty()) { return Response.status(401).build(); } @@ -503,7 +506,7 @@ private static UpdateUserRequestType updateUser(UserType existingUser, UserType public Response getRoles(@Context SecurityContext security, @PathParam("id") String id) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.getRoles"); Optional port = - setupFirmPort(firmFactory, ((EfspSecurityContext) security).getTylerUser()); + setupFirmPort(firmFactory, ((EfspSecurityContext) security).getUserCreds()); if (port.isEmpty()) { return Response.status(401).build(); } @@ -528,7 +531,7 @@ public Response addRoles( @Context SecurityContext security, @PathParam("id") String id, List toAdd) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.addRoles"); Optional port = - setupFirmPort(firmFactory, ((EfspSecurityContext) security).getTylerUser()); + setupFirmPort(firmFactory, ((EfspSecurityContext) security).getUserCreds()); if (port.isEmpty()) { return Response.status(401).build(); } @@ -562,7 +565,7 @@ public Response removeRoles( @Context SecurityContext security, @PathParam("id") String id, List toRm) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.removeRoles"); Optional port = - setupFirmPort(firmFactory, ((EfspSecurityContext) security).getTylerUser()); + setupFirmPort(firmFactory, ((EfspSecurityContext) security).getUserCreds()); if (port.isEmpty()) { return Response.status(401).build(); } @@ -631,9 +634,8 @@ public Response registerUser( MDC.put(MDCWrappers.OPERATION, "AdminUserService.registerUser"); final var regType = req.getRegistrationType(); boolean needsAuth = regType.equals(RegistrationType.FIRM_ADMIN_NEW_MEMBER); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional port = - setupFirmPort(firmFactory, tylerUser.map(u -> u.creds()), needsAuth); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional port = setupFirmPort(firmFactory, userCreds, needsAuth); if (port.isEmpty()) { return Response.status(401).build(); } @@ -726,7 +728,7 @@ private void logTylerErrorsWithContext(TylerErrorCodes.Error error, Registration public Response removeUser(@Context SecurityContext security, @PathParam("id") String id) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.removeUser"); Optional port = - setupFirmPort(firmFactory, ((EfspSecurityContext) security).getTylerUser()); + setupFirmPort(firmFactory, ((EfspSecurityContext) security).getUserCreds()); if (port.isEmpty()) { return Response.status(401).build(); } @@ -743,7 +745,7 @@ public Response removeUser(@Context SecurityContext security, @PathParam("id") S public Response getNotificationPreferenceList(@Context SecurityContext security) { MDC.put(MDCWrappers.OPERATION, "AdminUserService.getNotificationPreferenceList"); Optional port = - setupFirmPort(firmFactory, ((EfspSecurityContext) security).getTylerUser()); + setupFirmPort(firmFactory, ((EfspSecurityContext) security).getUserCreds()); if (port.isEmpty()) { return Response.status(401).build(); } @@ -754,7 +756,7 @@ public Response getNotificationPreferenceList(@Context SecurityContext security) /** Default needsSoapHeader to True: most ops need Tyler Authentication in the SOAP header. */ private Optional setupUserPort(EfspSecurityContext security) { - return setupUserPort(security.getTylerUser(), true); + return setupUserPort(security.getUserCreds(), true); } /** @@ -764,10 +766,10 @@ private Optional setupUserPort(EfspSecurityContext security) { * @param needsSoapHeader True if the operation needs Authenticated Tyler creds to work * @return false if setup didn't work, and subsequent service calls will likely fail */ - private Optional setupUserPort( - Optional tylerUser, boolean needsSoapHeader) { + private Optional setupUserPort(UserCreds userCreds, boolean needsSoapHeader) { if (needsSoapHeader) { - if (tylerUser.isEmpty()) { + List
headersList = userCreds.toHeaders(); + if (headersList.isEmpty()) { return Optional.empty(); } Consumer setup = @@ -780,7 +782,6 @@ private Optional setupUserPort( httpClientPolicy.setReceiveTimeout(180_000); http.setClient(httpClientPolicy); Map ctx = bp.getRequestContext(); - List
headersList = List.of(tylerUser.get().creds().toHeader()); ctx.put(Header.HEADER_LIST, headersList); }; return Optional.of(userFactory.makeUserClient(setup)); diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/ApiUserSettingsService.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/ApiUserSettingsService.java index 90f830cb4..82027ff72 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/ApiUserSettingsService.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/ApiUserSettingsService.java @@ -3,9 +3,9 @@ import com.webcohesion.enunciate.metadata.rs.ResourceGroup; import edu.suffolk.litlab.efsp.db.LoginDatabase; import edu.suffolk.litlab.efsp.db.model.AtRest; -import edu.suffolk.litlab.efsp.server.utils.EfspSecurityContext; +import edu.suffolk.litlab.efsp.server.auth.EfspSecurityContext; +import edu.suffolk.litlab.efsp.server.auth.NeedsAuthorization; import edu.suffolk.litlab.efsp.server.utils.EndpointReflection; -import edu.suffolk.litlab.efsp.server.utils.NeedsAuthorization; import jakarta.ws.rs.GET; import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/AuthenticationService.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/AuthenticationService.java index 9e3ec2aa1..b41dc3410 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/AuthenticationService.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/AuthenticationService.java @@ -12,6 +12,8 @@ import jakarta.ws.rs.POST; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; import java.util.Optional; @@ -56,17 +58,19 @@ public AuthenticationService(SecurityHub security) { */ @StatusCodes({@ResponseCode(code = 403, condition = "login information not valid")}) @POST - public Response authenticateUser(String loginInfo) { + public Response authenticateUser(@Context HttpHeaders headers, String loginInfo) { MDC.put(MDCWrappers.OPERATION, "AuthenticationService.authenticateUser"); ObjectMapper mapper = new ObjectMapper(); - String apiKey; + String apiKey = headers.getHeaderString("X-API-KEY"); try { JsonNode node = mapper.readTree(loginInfo); - if (!node.isObject() || !node.has("api_key") || !node.get("api_key").isTextual()) { - log.error("Call didn't pass in an api_key in the auth call"); - return Response.status(401).build(); + if (apiKey == null || apiKey.isBlank()) { + if (!node.isObject() || !node.has("api_key") || !node.get("api_key").isTextual()) { + log.error("Call didn't pass in an api_key in the auth call"); + return Response.status(401).build(); + } + apiKey = node.get("api_key").asText(); } - apiKey = node.get("api_key").asText(); if (apiKey == null || apiKey.isBlank()) { log.error("Call passed in a null / blank api_key"); return Response.status(401).build(); diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/CasesService.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/CasesService.java index 15f18cd6d..4664a8e44 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/CasesService.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/CasesService.java @@ -26,20 +26,19 @@ import ecf4.latest.tyler.efm.wsdl.webservicesprofile_implementation_4_0.CourtRecordMDEService; import edu.suffolk.litlab.efsp.Jurisdiction; import edu.suffolk.litlab.efsp.model.Name; -import edu.suffolk.litlab.efsp.server.auth.TylerLogin; +import edu.suffolk.litlab.efsp.server.auth.EfspSecurityContext; +import edu.suffolk.litlab.efsp.server.auth.NeedsAuthorization; +import edu.suffolk.litlab.efsp.server.auth.UserCreds; import edu.suffolk.litlab.efsp.server.ecf4.EcfCaseTypeFactory; import edu.suffolk.litlab.efsp.server.logging.MDCWrappers; import edu.suffolk.litlab.efsp.server.utils.EndpointReflection; -import edu.suffolk.litlab.efsp.server.utils.NeedsAuthorization; import edu.suffolk.litlab.efsp.server.utils.ServiceHelpers; import edu.suffolk.litlab.efsp.server.utils.ServiceHelpers.FileableCourtType; import edu.suffolk.litlab.efsp.tyler.Ecf4Helper; import edu.suffolk.litlab.efsp.tyler.SoapClientChooser; -import edu.suffolk.litlab.efsp.tyler.TylerUserNamePassword; import edu.suffolk.litlab.efsp.tyler.ecfcodes.CodeDatabase; import edu.suffolk.litlab.efsp.tyler.ecfcodes.CourtLocationInfo; import edu.suffolk.litlab.efsp.tyler.ecfcodes.DataFieldRow; -import edu.suffolk.litlab.efsp.utils.Hasher; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; @@ -49,6 +48,7 @@ import jakarta.ws.rs.core.HttpHeaders; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.SecurityContext; import jakarta.xml.bind.JAXBElement; import jakarta.xml.ws.BindingProvider; import java.lang.reflect.Method; @@ -84,11 +84,9 @@ public class CasesService { new ecf4.latest.oasis.names.tc.legalxml_courtfiling.schema.xsd.commontypes_4 .ObjectFactory(); private final Supplier cdSupplier; - private final Jurisdiction jurisdiction; private final EndpointReflection ef; public CasesService(Jurisdiction jurisdiction, Supplier cdSupplier) { - this.jurisdiction = jurisdiction; Optional maybeRecords = SoapClientChooser.getCourtRecordFactory(jurisdiction); if (maybeRecords.isEmpty()) { @@ -148,7 +146,7 @@ public Response getEndpointsUnderCourt(@PathParam("court_id") String courtId) { @Path("/courts/{court_id}/cases") @NeedsAuthorization public Response getCaseList( - @Context HttpHeaders httpHeaders, + @Context SecurityContext security, @PathParam("court_id") String courtId, @QueryParam("docket_number") String docketId, @QueryParam("business_name") String businessName, @@ -157,7 +155,8 @@ public Response getCaseList( @QueryParam("last_name") String lastName) throws JsonProcessingException { MDC.put(MDCWrappers.OPERATION, "CasesService.getCaseList"); - Optional maybePort = setupRecordPort(httpHeaders); + EfspSecurityContext efspSecurity = (EfspSecurityContext) security; + Optional maybePort = setupRecordPort(efspSecurity.getUserCreds()); if (maybePort.isEmpty()) { return Response.status(401).build(); } @@ -253,11 +252,12 @@ public Response getCaseList( @Path("/courts/{court_id}/cases/{case_tracking_id}") @NeedsAuthorization public Response getCase( - @Context HttpHeaders httpHeaders, + @Context SecurityContext security, @PathParam("court_id") String courtId, @PathParam("case_tracking_id") String caseId) { MDC.put(MDCWrappers.OPERATION, "CasesService.getCase"); - Optional maybePort = setupRecordPort(httpHeaders); + EfspSecurityContext efspSecurity = (EfspSecurityContext) security; + Optional maybePort = setupRecordPort(efspSecurity.getUserCreds()); if (maybePort.isEmpty()) { return Response.status(401).build(); } @@ -340,11 +340,12 @@ public Response getDocument( @Path("/courts/{court_id}/service-contacts/{service_contact_id}/cases") @NeedsAuthorization public Response getServiceAttachCaseList( - @Context HttpHeaders httpHeaders, + @Context SecurityContext security, @PathParam("court_id") String courtId, @PathParam("service_contact_id") String serviceId) { MDC.put(MDCWrappers.OPERATION, "CasesService.getServiceAttachCaseList"); - Optional maybePort = setupRecordPort(httpHeaders); + EfspSecurityContext efspSecurity = (EfspSecurityContext) security; + Optional maybePort = setupRecordPort(efspSecurity.getUserCreds()); if (maybePort.isEmpty()) { return Response.status(401).build(); } @@ -368,11 +369,12 @@ public Response getServiceAttachCaseList( @Path("/courts/{court_id}/cases/{case_tracking_id}/service-information") @NeedsAuthorization public Response getServiceInformation( - @Context HttpHeaders httpHeaders, + @Context SecurityContext security, @PathParam("court_id") String courtId, @PathParam("case_tracking_id") String caseId) { MDC.put(MDCWrappers.OPERATION, "CasesService.getServiceInformation"); - Optional maybePort = setupRecordPort(httpHeaders); + EfspSecurityContext efspSecurity = (EfspSecurityContext) security; + Optional maybePort = setupRecordPort(efspSecurity.getUserCreds()); if (maybePort.isEmpty()) { return Response.status(401).build(); } @@ -397,11 +399,12 @@ public Response getServiceInformation( @Path("/courts/{court_id}/cases/{case_tracking_id}/service-information-history") @NeedsAuthorization public Response getServiceInformationHistory( - @Context HttpHeaders httpHeaders, + @Context SecurityContext security, @PathParam("court_id") String courtId, @PathParam("case_tracking_id") String caseId) { MDC.put(MDCWrappers.OPERATION, "CasesService.getServiceInformationHistory"); - Optional maybePort = setupRecordPort(httpHeaders); + EfspSecurityContext efspSecurity = (EfspSecurityContext) security; + Optional maybePort = setupRecordPort(efspSecurity.getUserCreds()); if (maybePort.isEmpty()) { return Response.status(401).build(); } @@ -429,13 +432,8 @@ private static boolean hasError(QueryResponseMessageType resp) { && !resp.getError().get(0).getErrorCode().getValue().equals("0")); } - private Optional setupRecordPort(HttpHeaders httpHeaders) { - String tylerToken = - httpHeaders.getHeaderString(TylerLogin.getHeaderKeyFromJurisdiction(jurisdiction)); - MDC.put(MDCWrappers.USER_ID, Hasher.makeHash(tylerToken)); - Optional creds = - TylerUserNamePassword.userCredsFromAuthorization(tylerToken); - if (creds.isEmpty()) { + private Optional setupRecordPort(UserCreds userCreds) { + if (userCreds.toHeaders().isEmpty()) { log.warn("No creds?"); return Optional.empty(); } @@ -450,7 +448,7 @@ private Optional setupRecordPort(HttpHeaders httpHeaders) { httpClientPolicy.setReceiveTimeout(180_000); http.setClient(httpClientPolicy); - ServiceHelpers.setupServicePort((BindingProvider) port, creds.get()); + ServiceHelpers.setupServicePort((BindingProvider) port, userCreds); return Optional.of(port); } } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/CourtSchedulingService.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/CourtSchedulingService.java index cf24f9b9e..44e487ebe 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/CourtSchedulingService.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/CourtSchedulingService.java @@ -40,6 +40,9 @@ import edu.suffolk.litlab.efsp.model.FilingInformation; import edu.suffolk.litlab.efsp.model.PartyId; import edu.suffolk.litlab.efsp.model.Person; +import edu.suffolk.litlab.efsp.server.auth.EfspSecurityContext; +import edu.suffolk.litlab.efsp.server.auth.NeedsAuthorization; +import edu.suffolk.litlab.efsp.server.auth.UserCreds; import edu.suffolk.litlab.efsp.server.ecf4.EcfCaseTypeFactory; import edu.suffolk.litlab.efsp.server.ecf4.EcfCourtSpecificSerializer; import edu.suffolk.litlab.efsp.server.ecf4.Ecfv5CaseTypeFactory; @@ -47,16 +50,12 @@ import edu.suffolk.litlab.efsp.server.ecf4.TylerEcf4Helper; import edu.suffolk.litlab.efsp.server.logging.MDCWrappers; import edu.suffolk.litlab.efsp.server.utils.Ecfv5XmlHelper; -import edu.suffolk.litlab.efsp.server.utils.EfspSecurityContext; import edu.suffolk.litlab.efsp.server.utils.EndpointReflection; -import edu.suffolk.litlab.efsp.server.utils.NeedsAuthorization; import edu.suffolk.litlab.efsp.server.utils.ServiceHelpers; -import edu.suffolk.litlab.efsp.server.utils.TylerUserFromServer; import edu.suffolk.litlab.efsp.tyler.Ecf4Helper; import edu.suffolk.litlab.efsp.tyler.SoapClientChooser; import edu.suffolk.litlab.efsp.tyler.TylerClients; import edu.suffolk.litlab.efsp.tyler.TylerFirmFactory; -import edu.suffolk.litlab.efsp.tyler.TylerUserNamePassword; import edu.suffolk.litlab.efsp.tyler.ecfcodes.CaseCategory; import edu.suffolk.litlab.efsp.tyler.ecfcodes.CodeDatabase; import edu.suffolk.litlab.efsp.tyler.ecfcodes.ComboCaseCodes; @@ -259,7 +258,7 @@ public Response getReturnDate( String allVars) throws SQLException, JAXBException { MDC.put(MDCWrappers.OPERATION, "CourtSchedulingService.getReturnDate"); - Optional tylerUser = ((EfspSecurityContext) security).getTylerUser(); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); Optional maybeServ = setupSchedulingPort((EfspSecurityContext) security); if (maybeServ.isEmpty()) { return Response.status(401).build(); @@ -280,9 +279,9 @@ public Response getReturnDate( mediaType = MediaType.valueOf("application/json"); } InfoCollector collector = new FailFastCollector(); - boolean isIndividual = getIsIndividual(firmFactory, tylerUser.map(u -> u.creds())); + boolean isIndividual = getIsIndividual(firmFactory, userCreds); - var filingPort = setupFilingPort(tylerUser); + var filingPort = setupFilingPort(userCreds); if (filingPort.isEmpty()) { return Response.status(401).entity("Not logged in to file with " + courtId).build(); } @@ -316,7 +315,7 @@ public Response getReturnDate( Stream.concat(info.getNewPlaintiffs().stream(), info.getNewDefendants().stream()) .toList(); if (!isFirstIndexedFiling) { - Optional recordPort = setupRecordPort(tylerUser); + Optional recordPort = setupRecordPort(userCreds); if (recordPort.isEmpty()) { return Response.status(500) .entity("Can't make connection to retrieve court records for subsequent case") @@ -607,7 +606,7 @@ public Response reserveCourtDateSync( } private Optional setupSchedulingPort(EfspSecurityContext security) { - Optional creds = security.getTylerUser().map(u -> u.creds()); + Optional creds = security.getTylerUser().map(u -> u.creds()); if (creds.isEmpty()) { log.warn("No creds?"); return Optional.empty(); @@ -615,20 +614,16 @@ private Optional setupSchedulingPort(EfspSecurityContext sec CourtSchedulingMDE serv = schedFactory.getCourtSchedulingMDEPort(); ServiceHelpers.setupServicePort((BindingProvider) serv); Map ctx = ((BindingProvider) serv).getRequestContext(); - List
headersList = List.of(creds.get().toHeader()); + List
headersList = creds.get().toHeaders(); ctx.put(Header.HEADER_LIST, headersList); return Optional.of(serv); } - private Optional setupRecordPort(Optional tylerUser) { - if (tylerUser.isEmpty()) { - return Optional.empty(); - } - + private Optional setupRecordPort(UserCreds userCreds) { CourtRecordMDEPort port = recordFactory.getCourtRecordMDEPort(); ServiceHelpers.setupServicePort((BindingProvider) port); Map ctx = ((BindingProvider) port).getRequestContext(); - List
headersList = List.of(tylerUser.get().creds().toHeader()); + List
headersList = userCreds.toHeaders(); ctx.put(Header.HEADER_LIST, headersList); return Optional.of(port); } @@ -650,14 +645,10 @@ private static boolean hasError(ResponseMessageType rt) { || (!errorCodeText.isBlank() && !errorCodeText.equals("0")); } - private Optional setupFilingPort(Optional tylerUser) { - if (tylerUser.isEmpty()) { - return Optional.empty(); - } - + private Optional setupFilingPort(UserCreds userCreds) { FilingReviewMDEPort port = makeFilingPort(); Map ctx = ((BindingProvider) port).getRequestContext(); - List
headersList = List.of(tylerUser.get().creds().toHeader()); + List
headersList = userCreds.toHeaders(); ctx.put(Header.HEADER_LIST, headersList); return Optional.of(port); } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/FilingReviewService.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/FilingReviewService.java index 3f8314624..a1c1e9768 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/FilingReviewService.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/FilingReviewService.java @@ -11,15 +11,14 @@ import edu.suffolk.litlab.efsp.model.FilingInformation; import edu.suffolk.litlab.efsp.model.FilingResult; import edu.suffolk.litlab.efsp.model.Person; -import edu.suffolk.litlab.efsp.server.auth.TylerLogin; +import edu.suffolk.litlab.efsp.server.auth.EfspSecurityContext; +import edu.suffolk.litlab.efsp.server.auth.NeedsAuthorization; +import edu.suffolk.litlab.efsp.server.auth.UserCreds; import edu.suffolk.litlab.efsp.server.logging.MDCWrappers; import edu.suffolk.litlab.efsp.server.services.api.EfmFilingInterface; import edu.suffolk.litlab.efsp.server.setup.EfmRestCallbackInterface; -import edu.suffolk.litlab.efsp.server.utils.EfspSecurityContext; import edu.suffolk.litlab.efsp.server.utils.EndpointReflection; -import edu.suffolk.litlab.efsp.server.utils.NeedsAuthorization; import edu.suffolk.litlab.efsp.server.utils.OrgMessageSender; -import edu.suffolk.litlab.efsp.tyler.TylerUserNamePassword; import edu.suffolk.litlab.efsp.utils.FailFastCollector; import edu.suffolk.litlab.efsp.utils.FilingError; import edu.suffolk.litlab.efsp.utils.InfoCollector; @@ -69,7 +68,6 @@ public class FilingReviewService { private final OrgMessageSender msgSender; private final Supplier udSupplier; private final EndpointReflection ef; - private final Jurisdiction jurisdiction; public FilingReviewService( Jurisdiction jurisdiction, @@ -83,7 +81,6 @@ public FilingReviewService( this.callbackInterfaces = callbackInterfaces; this.udSupplier = udSupplier; this.msgSender = msgSender; - this.jurisdiction = jurisdiction; this.ef = new EndpointReflection("/jurisdictions/" + jurisdiction.getName() + "/filingreview"); } @@ -133,11 +130,8 @@ public Response getFilingStatus( } EfmFilingInterface filer = checked.unwrapOrElseThrow(); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - if (tylerUser.isEmpty()) { - return Response.status(401).entity("Not logged in to file with " + courtId).build(); - } - var toRet = filer.getFilingStatus(courtId, filingId, tylerUser.get().creds()); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + var toRet = filer.getFilingStatus(courtId, filingId, userCreds); return toRet; } @@ -157,15 +151,12 @@ public Response getFilingList( return checked.unwrapErrOrElseThrow(); } EfmFilingInterface filer = filingInterfaces.get(courtId); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - if (tylerUser.isEmpty()) { - return Response.status(401).entity("Not logged in to file with " + courtId).build(); - } + var userCreds = ((EfspSecurityContext) security).getUserCreds(); try { LocalDate startDate = (startStr != null) ? LocalDate.parse(startStr) : null; LocalDate beforeDate = (beforeStr != null) ? LocalDate.parse(beforeStr) : null; // beforeDate is exclusive! - return filer.getFilingList(courtId, userId, startDate, beforeDate, tylerUser.get().creds()); + return filer.getFilingList(courtId, userId, startDate, beforeDate, userCreds); } catch (DateTimeParseException ex) { return Response.status(400) .entity( @@ -189,20 +180,18 @@ public Response checkFilingForReview( if (mediaType == null) { mediaType = MediaType.valueOf("application/json"); } - String userUuid = httpHeaders.getHeaderString(TylerLogin.getHeaderId(jurisdiction)); + var efspSecurity = (EfspSecurityContext) security; + var userUuid = efspSecurity.getUserId(); Result checked = checkFilingInterfaces(courtId); if (checked.isErr()) { return checked.unwrapErrOrElseThrow(); } EfmFilingInterface filer = checked.unwrapOrElseThrow(); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - if (tylerUser.isEmpty()) { - return Response.status(401).entity("Not logged in to file with " + courtId).build(); - } + var userCreds = efspSecurity.getUserCreds(); if (!converterMap.containsKey(mediaType.toString())) { return Response.status(415).entity("We only support " + converterMap.keySet()).build(); } - Result maybeParser = makeParser(courtId, tylerUser.get().creds(), filer); + Result maybeParser = makeParser(courtId, userCreds, filer); if (maybeParser.isErr()) { return maybeParser.unwrapErrOrElseThrow(); } @@ -219,7 +208,7 @@ public Response checkFilingForReview( FilingInformation info = res.unwrapOrElseThrow(); info.setCourtLocation(courtId); Result resEfm = - filer.checkFiling(info, tylerUser.get().creds(), userUuid, collector); + filer.checkFiling(info, userCreds, userUuid, collector); if (resEfm.isErr()) { log.error("Error on checkFiling: {}", resEfm.toString()); return Response.ok(collector.jsonSummary()).build(); @@ -249,14 +238,11 @@ public Response calculateFilingFees( return checked.unwrapErrOrElseThrow(); } EfmFilingInterface filer = checked.unwrapOrElseThrow(); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - if (tylerUser.isEmpty()) { - return Response.status(401).entity("Not logged in to file with " + courtId).build(); - } + var userCreds = ((EfspSecurityContext) security).getUserCreds(); if (!converterMap.containsKey(mediaType.toString())) { return Response.status(415).entity("We only support " + converterMap.keySet()).build(); } - Result maybeParser = makeParser(courtId, tylerUser.get().creds(), filer); + Result maybeParser = makeParser(courtId, userCreds, filer); if (maybeParser.isErr()) { return maybeParser.unwrapErrOrElseThrow(); } @@ -272,7 +258,7 @@ public Response calculateFilingFees( } FilingInformation info = res.unwrapOrElseThrow(); info.setCourtLocation(courtId); - Result fees = filer.getFilingFees(info, tylerUser.get().creds()); + Result fees = filer.getFilingFees(info, userCreds); return fees.match(err -> Response.status(400).entity(err.toJson()).build(), respon -> respon); } finally { parser.close(); @@ -299,14 +285,11 @@ public Response getServiceTypes( return checked.unwrapErrOrElseThrow(); } EfmFilingInterface filer = checked.unwrapOrElseThrow(); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - if (tylerUser.isEmpty()) { - return Response.status(401).entity("Not logged in to file with " + courtId).build(); - } + var userCreds = ((EfspSecurityContext) security).getUserCreds(); if (!converterMap.containsKey(mediaType.toString())) { return Response.status(415).entity("We only support " + converterMap.keySet()).build(); } - Result maybeParser = makeParser(courtId, tylerUser.get().creds(), filer); + Result maybeParser = makeParser(courtId, userCreds, filer); if (maybeParser.isErr()) { return maybeParser.unwrapErrOrElseThrow(); } @@ -320,7 +303,7 @@ public Response getServiceTypes( } FilingInformation info = res.unwrapOrElseThrow(); info.setCourtLocation(courtId); - Result fees = filer.getServiceTypes(info, tylerUser.get().creds()); + Result fees = filer.getServiceTypes(info, userCreds); return fees.match(err -> Response.status(400).entity(err.toJson()).build(), respon -> respon); } finally { parser.close(); @@ -338,12 +321,9 @@ public Response getPolicy( return checked.unwrapErrOrElseThrow(); } EfmFilingInterface filer = checked.unwrapOrElseThrow(); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - if (tylerUser.isEmpty()) { - return Response.status(401).entity("Not logged in to file with " + courtId).build(); - } + var userCreds = ((EfspSecurityContext) security).getUserCreds(); - var toRet = filer.getPolicy(courtId, tylerUser.get().creds()); + var toRet = filer.getPolicy(courtId, userCreds); return toRet; } @@ -402,26 +382,22 @@ private Response fileOrServe( if (mediaType == null) { mediaType = MediaType.valueOf("application/json"); } - String userUuid = httpHeaders.getHeaderString(TylerLogin.getHeaderId(jurisdiction)); + var userUuid = security.getUserId(); Result checked = checkFilingInterfaces(courtId); if (checked.isErr()) { return checked.unwrapErrOrElseThrow(); } EfmFilingInterface filer = checked.unwrapOrElseThrow(); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - if (tylerUser.isEmpty()) { - return Response.status(401).entity("Not logged in to file with " + courtId).build(); - } + var userCreds = ((EfspSecurityContext) security).getUserCreds(); Result maybeInfo = - parseFiling(allVars, filer, courtId, tylerUser.get().creds(), mediaType); + parseFiling(allVars, filer, courtId, userCreds, mediaType); if (maybeInfo.isErr()) { return maybeInfo.unwrapErrOrElseThrow(); } FilingInformation info = maybeInfo.unwrapOrElseThrow(); info.setCourtLocation(courtId); Result result = - filer.sendFiling( - info, tylerUser.get().creds(), userUuid, EfmFilingInterface.ApiChoice.FileApi); + filer.sendFiling(info, userCreds, userUuid, EfmFilingInterface.ApiChoice.FileApi); if (result.isErr()) { return Response.status(500).entity(result.unwrapErrOrElseThrow().toJson()).build(); } @@ -452,7 +428,7 @@ private Response fileOrServe( user.getContactInfo().getEmail().orElse(""), filingIds, security.getServerId(), - tylerUser.get().creds().toString(), + userCreds.toString(), info.getCaseTypeCode().code, courtId, ts, @@ -491,7 +467,7 @@ private Result parseFiling( String allVars, EfmFilingInterface filer, String courtId, - TylerUserNamePassword activeToken, + UserCreds activeToken, MediaType mediaType) { log.trace("Court id: {}", courtId); if (!converterMap.containsKey(mediaType.toString())) { @@ -536,11 +512,8 @@ public Response getFilingDetails( return checked.unwrapErrOrElseThrow(); } EfmFilingInterface filer = checked.unwrapOrElseThrow(); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - if (tylerUser.isEmpty()) { - return Response.status(401).entity("Not logged in to file with " + courtId).build(); - } - return filer.getFilingDetails(courtId, filingId, tylerUser.get().creds()); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + return filer.getFilingDetails(courtId, filingId, userCreds); } finally { } } @@ -559,11 +532,8 @@ public Response getFilingService( return checked.unwrapErrOrElseThrow(); } EfmFilingInterface filer = checked.unwrapOrElseThrow(); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - if (tylerUser.isEmpty()) { - return Response.status(401).entity("Not logged in to file with " + courtId).build(); - } - var toRet = filer.getFilingService(courtId, filingId, contactId, tylerUser.get().creds()); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + var toRet = filer.getFilingService(courtId, filingId, contactId, userCreds); return toRet; } @@ -580,11 +550,8 @@ public Response cancelFiling( return checked.unwrapErrOrElseThrow(); } EfmFilingInterface filer = checked.unwrapOrElseThrow(); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - if (tylerUser.isEmpty()) { - return Response.status(401).entity("Not logged in to file with " + courtId).build(); - } - var toRet = filer.cancelFiling(courtId, filingId, tylerUser.get().creds()); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + var toRet = filer.cancelFiling(courtId, filingId, userCreds); return toRet; } @@ -596,7 +563,7 @@ private Result checkFilingInterfaces(String courtI } private Result makeParser( - String courtId, TylerUserNamePassword creds, EfmFilingInterface filer) { + String courtId, UserCreds creds, EfmFilingInterface filer) { var parser = filer.getParser(courtId, creds); if (parser.isEmpty()) { return Result.err(Response.status(404).entity("Cannot send filing to " + courtId).build()); diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/FirmAttorneyAndServiceService.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/FirmAttorneyAndServiceService.java index cf6d4416b..33fed688d 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/FirmAttorneyAndServiceService.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/FirmAttorneyAndServiceService.java @@ -9,11 +9,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.webcohesion.enunciate.metadata.rs.ResourceGroup; import edu.suffolk.litlab.efsp.Jurisdiction; +import edu.suffolk.litlab.efsp.server.auth.EfspSecurityContext; +import edu.suffolk.litlab.efsp.server.auth.NeedsAuthorization; import edu.suffolk.litlab.efsp.server.logging.MDCWrappers; import edu.suffolk.litlab.efsp.server.services.api.ServiceContactInput; -import edu.suffolk.litlab.efsp.server.utils.EfspSecurityContext; import edu.suffolk.litlab.efsp.server.utils.EndpointReflection; -import edu.suffolk.litlab.efsp.server.utils.NeedsAuthorization; import edu.suffolk.litlab.efsp.tyler.TylerClients; import edu.suffolk.litlab.efsp.tyler.TylerErrorCodes; import edu.suffolk.litlab.efsp.tyler.TylerFirmClient; @@ -112,8 +112,8 @@ public Response getAll() { @NeedsAuthorization public Response getSelfFirm(@Context SecurityContext security) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.getSelfFirm"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(401).build(); } @@ -127,8 +127,8 @@ public Response getSelfFirm(@Context SecurityContext security) { @NeedsAuthorization public Response updateFirm(@Context SecurityContext security, String json) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.updateFirm"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(401).build(); } @@ -166,8 +166,8 @@ public Response updateFirm(@Context SecurityContext security, String json) { @NeedsAuthorization public Response getAttorneyList(@Context SecurityContext security) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.getAttorneyList"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -182,8 +182,8 @@ public Response getAttorneyList(@Context SecurityContext security) { public Response getAttorney( @Context SecurityContext security, @PathParam("attorney_id") String attorneyId) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.getAttorney"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -199,8 +199,8 @@ public Response getAttorney( @NeedsAuthorization public Response createAttorney(@Context SecurityContext security, AttorneyType attorney) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.createAttorney"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -234,8 +234,8 @@ public Response createAttorney(@Context SecurityContext security, AttorneyType a public Response updateAttorney( @Context SecurityContext security, @PathParam("attorney_id") String attorneyId, String json) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.updateAttorney"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -268,8 +268,8 @@ public Response updateAttorney( public Response removeAttorney( @Context SecurityContext security, @PathParam("attorney_id") String attorneyId) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.removeAttorney"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -285,8 +285,8 @@ public Response removeAttorney( @NeedsAuthorization public Response getServiceContactList(@Context SecurityContext security) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.getServiceContactList"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(401).build(); } @@ -300,8 +300,8 @@ public Response getServiceContactList(@Context SecurityContext security) { public Response getServiceContact( @Context SecurityContext security, @PathParam("contact_id") String contactId) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.getServiceContact"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(401).build(); } @@ -321,8 +321,8 @@ public Response getServiceContact( public Response removeServiceContact( @Context SecurityContext security, @PathParam("contact_id") String contactId) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.removeServiceContact"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(401).build(); } @@ -340,8 +340,8 @@ public Response createServiceContact(@Context SecurityContext security, String s try { ServiceContactInput input = new ObjectMapper().readValue(strInput, ServiceContactInput.class); MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.createServiceContact"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(401).build(); } @@ -381,8 +381,8 @@ public Response createServiceContact(@Context SecurityContext security, String s public Response attachServiceContact( @Context SecurityContext security, @PathParam("contact_id") String contactId, String json) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.attachServiceContact"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(401).build(); } @@ -424,8 +424,8 @@ public Response detachServiceContact( @PathParam("case_id") String caseId, @QueryParam("case_party_id") String casePartyId) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.detachServiceContact"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(401).build(); } @@ -446,8 +446,8 @@ public Response detachServiceContact( public Response updateServiceContact( @Context SecurityContext security, @PathParam("contact_id") String contactId, String json) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.updateServiceContact"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(401).build(); } @@ -494,8 +494,8 @@ public Response updateServiceContact( @NeedsAuthorization public Response getPublicList(@Context SecurityContext security, String json) { MDC.put(MDCWrappers.OPERATION, "FirmAttorneyAndServiceService.getPublicList"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(401).build(); } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/JurisdictionServiceHandle.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/JurisdictionServiceHandle.java index 8df019ce0..6411e7667 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/JurisdictionServiceHandle.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/JurisdictionServiceHandle.java @@ -65,6 +65,22 @@ public JurisdictionServiceHandle( Optional.of(p)); } + public JurisdictionServiceHandle( + Jurisdiction jurisdiction, + FilingReviewService filingReview, + CasesService cases, + CodesService codes) { + this( + jurisdiction, + Optional.empty(), + Optional.of(cases), + Optional.of(codes), + Optional.empty(), + filingReview, + Optional.empty(), + Optional.empty()); + } + public JurisdictionServiceHandle( Jurisdiction jurisdiction, FilingReviewService filingReview, CodesService codes) { this( diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/MessageSettingsService.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/MessageSettingsService.java index 4b621150f..ce41d04c9 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/MessageSettingsService.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/MessageSettingsService.java @@ -5,10 +5,10 @@ import com.fasterxml.jackson.databind.ObjectMapper; import edu.suffolk.litlab.efsp.db.MessageSettingsDatabase; import edu.suffolk.litlab.efsp.db.model.MessageInfo; +import edu.suffolk.litlab.efsp.server.auth.EfspSecurityContext; +import edu.suffolk.litlab.efsp.server.auth.NeedsAuthorization; import edu.suffolk.litlab.efsp.server.logging.MDCWrappers; -import edu.suffolk.litlab.efsp.server.utils.EfspSecurityContext; import edu.suffolk.litlab.efsp.server.utils.EndpointReflection; -import edu.suffolk.litlab.efsp.server.utils.NeedsAuthorization; import edu.suffolk.litlab.efsp.server.utils.OrgMessageSender; import jakarta.ws.rs.GET; import jakarta.ws.rs.PATCH; diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/PaymentsService.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/PaymentsService.java index 804f8114b..f698f1d03 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/PaymentsService.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/PaymentsService.java @@ -11,17 +11,18 @@ import com.webcohesion.enunciate.metadata.rs.ResponseCode; import com.webcohesion.enunciate.metadata.rs.StatusCodes; import edu.suffolk.litlab.efsp.Jurisdiction; +import edu.suffolk.litlab.efsp.server.auth.EfspSecurityContext; +import edu.suffolk.litlab.efsp.server.auth.NeedsAuthorization; +import edu.suffolk.litlab.efsp.server.auth.NullUserCreds; +import edu.suffolk.litlab.efsp.server.auth.UserNamePassword; import edu.suffolk.litlab.efsp.server.logging.MDCWrappers; -import edu.suffolk.litlab.efsp.server.utils.EfspSecurityContext; import edu.suffolk.litlab.efsp.server.utils.EndpointReflection; -import edu.suffolk.litlab.efsp.server.utils.NeedsAuthorization; import edu.suffolk.litlab.efsp.server.utils.ServiceHelpers; import edu.suffolk.litlab.efsp.stdlib.RandomString; import edu.suffolk.litlab.efsp.tyler.TylerClients; import edu.suffolk.litlab.efsp.tyler.TylerErrorCodes; import edu.suffolk.litlab.efsp.tyler.TylerFirmClient; import edu.suffolk.litlab.efsp.tyler.TylerFirmFactory; -import edu.suffolk.litlab.efsp.tyler.TylerUserNamePassword; import edu.suffolk.litlab.efsp.tyler.ecfcodes.CodeDatabase; import edu.suffolk.litlab.efsp.utils.Hasher; import jakarta.ws.rs.Consumes; @@ -146,8 +147,8 @@ public Response getAll() { @NeedsAuthorization public Response getGlobalPaymentList(@Context SecurityContext security) { MDC.put(MDCWrappers.OPERATION, "PaymentsService.getGlobalPaymentList"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -162,8 +163,8 @@ public Response getGlobalPaymentList(@Context SecurityContext security) { public Response getGlobalPaymentAccount( @Context SecurityContext security, @PathParam("account_id") String accountId) { MDC.put(MDCWrappers.OPERATION, "PaymentsService.getGlobalPaymentAccount"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -190,8 +191,8 @@ public Response getGlobalPaymentAccount( @NeedsAuthorization public Response createGlobalWaiverAccount(@Context SecurityContext security, String accountName) { MDC.put(MDCWrappers.OPERATION, "PaymentsService.createGlobalWaiverAccount"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -204,8 +205,8 @@ public Response createGlobalWaiverAccount(@Context SecurityContext security, Str public Response updateGlobalPaymentAccount( @Context SecurityContext security, @PathParam("account_id") String accountId, String json) { MDC.put(MDCWrappers.OPERATION, "PaymentsService.updateGlobalPaymentAccount"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -228,8 +229,8 @@ public Response updateGlobalPaymentAccount( public Response removeGlobalPaymentAccount( @Context SecurityContext security, @PathParam("account_id") String accountId) { MDC.put(MDCWrappers.OPERATION, "PaymentsService.removeGlobalPaymentAccount"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -246,8 +247,8 @@ public Response removeGlobalPaymentAccount( public Response getPaymentAccount( @Context SecurityContext security, @PathParam("account_id") String accountId) { MDC.put(MDCWrappers.OPERATION, "PaymentsService.getPaymentAccount"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -265,8 +266,8 @@ public Response getPaymentAccount( public Response removePaymentAccount( @Context SecurityContext security, @PathParam("account_id") String accountId) { MDC.put(MDCWrappers.OPERATION, "PaymentsService.removePaymentAccount"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -284,8 +285,8 @@ public Response getPaymentAccountList( @Context SecurityContext security, @DefaultValue("") @QueryParam("court_id") String courtId) throws SQLException { MDC.put(MDCWrappers.OPERATION, "PaymentsService.getPaymentAccountList"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -321,8 +322,8 @@ public Response getPaymentAccountList( @NeedsAuthorization public Response createWaiverAccount(@Context SecurityContext security, String accountName) { MDC.put(MDCWrappers.OPERATION, "PaymentsService.createWaiverAccount"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -344,8 +345,8 @@ public Response updatePaymentAccount( @Context SecurityContext security, @PathParam("account_id") String accountId, String json) throws JsonMappingException, JsonProcessingException { MDC.put(MDCWrappers.OPERATION, "PaymentsService.updatePaymentAccount"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = ServiceHelpers.setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = ServiceHelpers.setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -367,8 +368,8 @@ public Response updatePaymentAccount( @NeedsAuthorization public Response getPaymentAccountTypeList(@Context SecurityContext security) { MDC.put(MDCWrappers.OPERATION, "PaymentsService.getPaymentAccountTypeList"); - var tylerUser = ((EfspSecurityContext) security).getTylerUser(); - Optional firmPort = ServiceHelpers.setupFirmPort(firmFactory, tylerUser); + var userCreds = ((EfspSecurityContext) security).getUserCreds(); + Optional firmPort = ServiceHelpers.setupFirmPort(firmFactory, userCreds); if (firmPort.isEmpty()) { return Response.status(403).build(); } @@ -440,10 +441,10 @@ public Response redirectToToga( log.error(err); return Response.status(422).entity(errorHtml.formatted(err)).build(); } - var maybeCreds = TylerUserNamePassword.userCredsFromAuthorization(tylerInfo); + var maybeCreds = UserNamePassword.userCredsFromAuthorization(tylerInfo); Optional firmPort = - ServiceHelpers.setupFirmPort(firmFactory, maybeCreds, true); - if (firmPort.isEmpty()) { + ServiceHelpers.setupFirmPort(firmFactory, maybeCreds.orElse(new NullUserCreds()), true); + if (maybeCreds.isEmpty() || firmPort.isEmpty()) { String err = "Unable to use your login information with Tyler: will not be able to create the payment" + " account."; @@ -574,9 +575,9 @@ public Response makeNewPaymentAccount( return Response.status(404).entity(paymentsErrorHtml).build(); } TempAccount tempInfo = tempAccounts.get(resp.transactionId); - var maybeCreds = TylerUserNamePassword.userCredsFromAuthorization(tempInfo.loginInfo); + var maybeCreds = UserNamePassword.userCredsFromAuthorization(tempInfo.loginInfo); Optional maybeFirmPort = - ServiceHelpers.setupFirmPort(firmFactory, maybeCreds, true); + ServiceHelpers.setupFirmPort(firmFactory, maybeCreds.orElse(new NullUserCreds()), true); if (maybeFirmPort.isEmpty()) { log.warn("Couldn't get the firm port for {}", resp.transactionId); return Response.status(403).entity(paymentsErrorHtml).build(); diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/api/EfmFilingInterface.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/api/EfmFilingInterface.java index 8032debbb..f182491af 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/api/EfmFilingInterface.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/api/EfmFilingInterface.java @@ -5,7 +5,8 @@ import edu.suffolk.litlab.efsp.ecfcodes.CodesParser; import edu.suffolk.litlab.efsp.model.FilingInformation; import edu.suffolk.litlab.efsp.model.FilingResult; -import edu.suffolk.litlab.efsp.tyler.TylerUserNamePassword; +import edu.suffolk.litlab.efsp.server.auth.UserCreds; +import edu.suffolk.litlab.efsp.stdlib.NonEmptyString; import edu.suffolk.litlab.efsp.utils.FilingError; import edu.suffolk.litlab.efsp.utils.InfoCollector; import jakarta.ws.rs.core.Response; @@ -29,19 +30,17 @@ public enum ApiChoice { * the callbacks. If it's > 1, should be the same number as the FilingDocs in info */ public Result sendFiling( - FilingInformation info, TylerUserNamePassword creds, String userUuid, ApiChoice choice); + FilingInformation info, UserCreds creds, Optional userUuid, ApiChoice choice); public Result checkFiling( FilingInformation info, - TylerUserNamePassword creds, - String userUuid, + UserCreds creds, + Optional userUuid, InfoCollector collector); - public Result getFilingFees( - FilingInformation info, TylerUserNamePassword creds); + public Result getFilingFees(FilingInformation info, UserCreds creds); - public Result getServiceTypes( - FilingInformation info, TylerUserNamePassword creds); + public Result getServiceTypes(FilingInformation info, UserCreds creds); // TODO(brycew-later): make this a little more independent of HTTP public Response getFilingList( @@ -49,20 +48,20 @@ public Response getFilingList( String submitterId, LocalDate startDate, LocalDate beforeDate, - TylerUserNamePassword creds); + UserCreds creds); - public Response getFilingStatus(String courtId, String filingId, TylerUserNamePassword creds); + public Response getFilingStatus(String courtId, String filingId, UserCreds creds); - public Response getFilingDetails(String courtId, String filingId, TylerUserNamePassword creds); + public Response getFilingDetails(String courtId, String filingId, UserCreds creds); public Response getFilingService( - String courtId, String filingId, String contactId, TylerUserNamePassword creds); + String courtId, String filingId, String contactId, UserCreds creds); - public Response getPolicy(String courtId, TylerUserNamePassword creds); + public Response getPolicy(String courtId, UserCreds creds); - public Response cancelFiling(String courtId, String filingId, TylerUserNamePassword creds); + public Response cancelFiling(String courtId, String filingId, UserCreds creds); - public Optional getParser(String courtId, TylerUserNamePassword creds); + public Optional getParser(String courtId, UserCreds creds); /** * TYLER ONLY at the moment: returns a list of disclaimers that must be shown to the user before @@ -76,7 +75,4 @@ public Response getFilingService( /** Used to properly verify with the SecurityHub. */ public String getOrgName(); - - /** Used to get the proper header that contains the right token. */ - public String getHeaderKey(); } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/impl/Ecf4Filer.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/impl/Ecf4Filer.java index cdce9ad81..355084b7e 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/impl/Ecf4Filer.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/impl/Ecf4Filer.java @@ -52,14 +52,16 @@ import edu.suffolk.litlab.efsp.model.Name; import edu.suffolk.litlab.efsp.model.PartyId; import edu.suffolk.litlab.efsp.model.Person; -import edu.suffolk.litlab.efsp.server.auth.TylerLogin; +import edu.suffolk.litlab.efsp.server.auth.UserCreds; import edu.suffolk.litlab.efsp.server.ecf4.EcfCaseTypeFactory; import edu.suffolk.litlab.efsp.server.ecf4.EcfCourtSpecificSerializer; import edu.suffolk.litlab.efsp.server.ecf4.PaymentFactory; import edu.suffolk.litlab.efsp.server.ecf4.PolicyCacher; import edu.suffolk.litlab.efsp.server.ecf4.QueryType; import edu.suffolk.litlab.efsp.server.ecf4.TylerEcf4Helper; +import edu.suffolk.litlab.efsp.server.utils.ProxyServerException; import edu.suffolk.litlab.efsp.server.utils.ServiceHelpers; +import edu.suffolk.litlab.efsp.stdlib.NonEmptyString; import edu.suffolk.litlab.efsp.tyler.Ecf4Helper; import edu.suffolk.litlab.efsp.tyler.SoapClientChooser; import edu.suffolk.litlab.efsp.tyler.TylerAdminUserUtils; @@ -67,7 +69,6 @@ import edu.suffolk.litlab.efsp.tyler.TylerFirmFactory; import edu.suffolk.litlab.efsp.tyler.TylerUserClient; import edu.suffolk.litlab.efsp.tyler.TylerUserFactory; -import edu.suffolk.litlab.efsp.tyler.TylerUserNamePassword; import edu.suffolk.litlab.efsp.tyler.ecfcodes.CaseCategory; import edu.suffolk.litlab.efsp.tyler.ecfcodes.CaseType; import edu.suffolk.litlab.efsp.tyler.ecfcodes.CodeDatabase; @@ -111,7 +112,6 @@ public class Ecf4Filer extends EfmCheckableFilingInterface { private static Logger log = LoggerFactory.getLogger(Ecf4Filer.class); private final Supplier cdSupplier; - private final String headerKey; private final ecf4.latest.oasis.names.tc.legalxml_courtfiling.schema.xsd .filingstatusquerymessage_4.ObjectFactory statusObjFac; @@ -138,8 +138,6 @@ public Ecf4Filer( Jurisdiction jurisdiction, Supplier cdSupplier, PolicyCacher policyCacher) { this.jurisdiction = jurisdiction; this.cdSupplier = cdSupplier; - TylerLogin login = new TylerLogin(jurisdiction); - this.headerKey = login.getHeaderKey(); statusObjFac = new ecf4.latest.oasis.names.tc.legalxml_courtfiling.schema.xsd.filingstatusquerymessage_4 .ObjectFactory(); @@ -188,20 +186,14 @@ public Ecf4Filer( } } - @Override - public String getHeaderKey() { - return this.headerKey; - } - - public Optional getParser(String courtId, TylerUserNamePassword creds) { + public Optional getParser(String courtId, UserCreds creds) { CodeDatabase cd = cdSupplier.get(); return getParser(cd, courtId, creds); } - private Optional getParser( - CodeDatabase cd, String courtId, TylerUserNamePassword creds) { + private Optional getParser(CodeDatabase cd, String courtId, UserCreds creds) { var filingPort = setupFilingPort(creds); - boolean isIndividual = getIsIndividual(firmFactory, Optional.of(creds)); + boolean isIndividual = getIsIndividual(firmFactory, creds); var policy = policyCacher.getPolicyFor(filingPort, courtId).getDevelopmentPolicyParameters().getValue(); return TylerCodesParser.makeParser(cd, policy, courtId, isIndividual); @@ -216,7 +208,7 @@ public record CoreMessageAndNames( private CoreMessageAndNames prepareFiling( FilingInformation info, InfoCollector collector, - TylerUserNamePassword creds, + UserCreds creds, FilingReviewMDEPort filingPort, CourtRecordMDEPort recordPort, QueryType queryType) @@ -514,8 +506,8 @@ private Result serveFilingIfReady( CoreFilingMessageType cfm, FilingInformation info, InfoCollector collector, - TylerUserNamePassword creds, - String userUuid) { + UserCreds creds, + Optional userUuid) { ServiceMDEPort port = setupServicePort(creds); ServiceReceiptMessageType receipt = port.serveFiling(cfm); StringBuilder sb = new StringBuilder(); @@ -551,8 +543,8 @@ private Result serveFilingIfReady( public Result submitFilingIfReady( FilingInformation info, InfoCollector collector, - TylerUserNamePassword creds, - String userUuid, + UserCreds creds, + Optional userUuid, ApiChoice choice) { FilingReviewMDEPort filingPort; CoreFilingMessageType cfm; @@ -657,14 +649,14 @@ public Result submitFilingIfReady( } public Person repairLeadContact( - Optional maybeLeadContact, TylerUserNamePassword creds, String userUuid) { + Optional maybeLeadContact, UserCreds creds, Optional userUuid) { Supplier userInfo = () -> { - TylerUserClient userPort = setupUserPort(creds); - if (userUuid == null || userUuid.isBlank()) { + if (userUuid.isEmpty()) { return Person.TestPerson(new Name(""), "", false); } - return TylerAdminUserUtils.getUser(userPort, userUuid); + TylerUserClient userPort = setupUserPort(creds); + return TylerAdminUserUtils.getUser(userPort, userUuid.get().get()); }; Person leadContact = maybeLeadContact.orElseGet(userInfo); if (leadContact.getContactInfo().getEmail().isEmpty() @@ -675,8 +667,7 @@ public Person repairLeadContact( } @Override - public Result getFilingFees( - FilingInformation info, TylerUserNamePassword creds) { + public Result getFilingFees(FilingInformation info, UserCreds creds) { FailFastCollector collector = new FailFastCollector(); CoreFilingMessageType cfm; FilingReviewMDEPort filingPort = setupFilingPort(creds); @@ -748,8 +739,7 @@ private List getAllLocations() throws SQLException { } @Override - public Result getServiceTypes( - FilingInformation info, TylerUserNamePassword creds) { + public Result getServiceTypes(FilingInformation info, UserCreds creds) { Optional court = getCourtInfo(info); if (court.isEmpty()) { return Result.ok(Response.status(404).entity("No court " + info.getCourtLocation()).build()); @@ -789,7 +779,7 @@ public Response getFilingList( String submitterId, java.time.LocalDate startDate, java.time.LocalDate beforeDate, - TylerUserNamePassword creds) { + UserCreds creds) { try { List courtIds = getAllLocations(); if (courtId != null && !courtId.equals("0") && !courtIds.contains(courtId)) { @@ -870,7 +860,7 @@ public Response getFilingList( } @Override - public Response getFilingStatus(String courtId, String filingId, TylerUserNamePassword creds) { + public Response getFilingStatus(String courtId, String filingId, UserCreds creds) { try { List courtIds = getAllLocations(); if (!courtIds.contains(courtId)) { @@ -891,7 +881,7 @@ public Response getFilingStatus(String courtId, String filingId, TylerUserNamePa @Override public Response getFilingService( - String courtId, String filingId, String contactId, TylerUserNamePassword creds) { + String courtId, String filingId, String contactId, UserCreds creds) { FilingReviewMDEPort port = setupFilingPort(creds); FilingServiceQueryMessageType req = new FilingServiceQueryMessageType(); ServiceContactIdentificationType id = new ServiceContactIdentificationType(); @@ -904,7 +894,7 @@ public Response getFilingService( } @Override - public Response getFilingDetails(String courtId, String filingId, TylerUserNamePassword creds) { + public Response getFilingDetails(String courtId, String filingId, UserCreds creds) { try { List courtIds = getAllLocations(); if (!courtIds.contains(courtId)) { @@ -923,7 +913,7 @@ public Response getFilingDetails(String courtId, String filingId, TylerUserNameP } @Override - public Response getPolicy(String courtId, TylerUserNamePassword creds) { + public Response getPolicy(String courtId, UserCreds creds) { try { List courtIds = getAllLocations(); if (!courtIds.contains(courtId)) { @@ -939,7 +929,7 @@ public Response getPolicy(String courtId, TylerUserNamePassword creds) { } @Override - public Response cancelFiling(String courtId, String filingId, TylerUserNamePassword creds) { + public Response cancelFiling(String courtId, String filingId, UserCreds creds) { try { List courtIds = getAllLocations(); if (!courtIds.contains(courtId)) { @@ -977,7 +967,13 @@ private static T prep(T newMsg, String courtId) { return TylerEcf4Helper.prep(newMsg, courtId); } - private FilingReviewMDEPort setupFilingPort(TylerUserNamePassword creds) { + private FilingReviewMDEPort setupFilingPort(UserCreds creds) { + List
headersList = creds.toHeaders(); + if (headersList.isEmpty()) { + // We know we're in Tyler, which needs Headers. If it's actually a NullUserCred, need to stop + // here. + throw new ProxyServerException.AuthenticationNeeded(); + } FilingReviewMDEPort port = makeFilingPort(); Client client = ClientProxy.getClient(port); HTTPConduit http = (HTTPConduit) client.getConduit(); @@ -986,35 +982,35 @@ private FilingReviewMDEPort setupFilingPort(TylerUserNamePassword creds) { httpClientPolicy.setReceiveTimeout(180_000); http.setClient(httpClientPolicy); Map ctx = ((BindingProvider) port).getRequestContext(); - List
headersList = List.of(creds.toHeader()); + ctx.put(Header.HEADER_LIST, headersList); return port; } - private ServiceMDEPort setupServicePort(TylerUserNamePassword creds) { + private ServiceMDEPort setupServicePort(UserCreds creds) { ServiceMDEPort port = makeServicePort(); Map ctx = ((BindingProvider) port).getRequestContext(); - List
headersList = List.of(creds.toHeader()); + List
headersList = creds.toHeaders(); ctx.put(Header.HEADER_LIST, headersList); return port; } - private CourtRecordMDEPort setupRecordPort(TylerUserNamePassword creds) { + private CourtRecordMDEPort setupRecordPort(UserCreds creds) { CourtRecordMDEPort port = recordFactory.getCourtRecordMDEPort(); ServiceHelpers.setupServicePort((BindingProvider) port); Map ctx = ((BindingProvider) port).getRequestContext(); - List
headersList = List.of(creds.toHeader()); + List
headersList = creds.toHeaders(); ctx.put(Header.HEADER_LIST, headersList); return port; } - private TylerUserClient setupUserPort(TylerUserNamePassword creds) { + private TylerUserClient setupUserPort(UserCreds creds) { Consumer setup = (BindingProvider bp) -> { ServiceHelpers.setupServicePort(bp); ServiceHelpers.changeTimeout(bp, 180_000); Map ctx = bp.getRequestContext(); - List
headersList = List.of(creds.toHeader()); + List
headersList = creds.toHeaders(); ctx.put(Header.HEADER_LIST, headersList); }; return userFactory.makeUserClient(setup); diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/impl/EfmCheckableFilingInterface.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/impl/EfmCheckableFilingInterface.java index ca4befa1f..f9b3da4c7 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/impl/EfmCheckableFilingInterface.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/services/impl/EfmCheckableFilingInterface.java @@ -4,17 +4,22 @@ import com.hubspot.algebra.Result; import edu.suffolk.litlab.efsp.model.FilingInformation; import edu.suffolk.litlab.efsp.model.FilingResult; +import edu.suffolk.litlab.efsp.server.auth.UserCreds; import edu.suffolk.litlab.efsp.server.services.api.EfmFilingInterface; -import edu.suffolk.litlab.efsp.tyler.TylerUserNamePassword; +import edu.suffolk.litlab.efsp.stdlib.NonEmptyString; import edu.suffolk.litlab.efsp.utils.FailFastCollector; import edu.suffolk.litlab.efsp.utils.FilingError; import edu.suffolk.litlab.efsp.utils.InfoCollector; +import java.util.Optional; public abstract class EfmCheckableFilingInterface implements EfmFilingInterface { @Override public Result sendFiling( - FilingInformation info, TylerUserNamePassword creds, String userUuid, ApiChoice choice) { + FilingInformation info, + UserCreds creds, + Optional userUuid, + ApiChoice choice) { FailFastCollector collector = new FailFastCollector(); return submitFilingIfReady(info, collector, creds, userUuid, choice); } @@ -22,8 +27,8 @@ public Result sendFiling( @Override public Result checkFiling( FilingInformation info, - TylerUserNamePassword creds, - String userUuid, + UserCreds creds, + Optional userUuid, InfoCollector collector) { return submitFilingIfReady(info, collector, creds, userUuid, ApiChoice.FileApi) .mapOk(n -> null); @@ -39,7 +44,7 @@ public Result checkFiling( public abstract Result submitFilingIfReady( FilingInformation info, InfoCollector collector, - TylerUserNamePassword creds, - String userUuid, + UserCreds creds, + Optional userUuid, ApiChoice choice); } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/ProxyServerException.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/ProxyServerException.java new file mode 100644 index 000000000..beaf8c95f --- /dev/null +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/ProxyServerException.java @@ -0,0 +1,6 @@ +package edu.suffolk.litlab.efsp.server.utils; + +public sealed class ProxyServerException extends RuntimeException { + + public static final class AuthenticationNeeded extends ProxyServerException {} +} diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/ProxyServerExceptionMapper.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/ProxyServerExceptionMapper.java new file mode 100644 index 000000000..d0e8518dc --- /dev/null +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/ProxyServerExceptionMapper.java @@ -0,0 +1,21 @@ +package edu.suffolk.litlab.efsp.server.utils; + +import edu.suffolk.litlab.efsp.server.utils.ProxyServerException.AuthenticationNeeded; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.ExceptionMapper; +import jakarta.ws.rs.ext.Provider; + +@Provider +public class ProxyServerExceptionMapper implements ExceptionMapper { + + @Override + public Response toResponse(ProxyServerException exception) { + return switch (exception) { + case AuthenticationNeeded n -> + Response.status(Response.Status.UNAUTHORIZED) + .entity("Need to be logged in to file") + .build(); + default -> Response.status(500).build(); + }; + } +} diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/ServiceHelpers.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/ServiceHelpers.java index 14b678d5e..4367daa45 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/ServiceHelpers.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/ServiceHelpers.java @@ -3,10 +3,10 @@ import static edu.suffolk.litlab.efsp.stdlib.StdLib.GetEnv; import edu.suffolk.litlab.efsp.ecfcodes.NameAndCode; +import edu.suffolk.litlab.efsp.server.auth.UserCreds; import edu.suffolk.litlab.efsp.tyler.TylerErrorCodes; import edu.suffolk.litlab.efsp.tyler.TylerFirmClient; import edu.suffolk.litlab.efsp.tyler.TylerFirmFactory; -import edu.suffolk.litlab.efsp.tyler.TylerUserNamePassword; import edu.suffolk.litlab.efsp.tyler.ecfcodes.CodeDatabase; import jakarta.ws.rs.core.Response; import jakarta.xml.ws.BindingProvider; @@ -69,8 +69,8 @@ public static void setupServicePort(BindingProvider bp) { ctx.put("set-jaxb-validation-event-handler", "false"); } - public static void setupServicePort(BindingProvider bp, TylerUserNamePassword creds) { - setupServicePort(bp, List.of(creds.toHeader())); + public static void setupServicePort(BindingProvider bp, UserCreds creds) { + setupServicePort(bp, creds.toHeaders()); } public static void setupServicePort(BindingProvider bp, List
headerList) { @@ -130,9 +130,8 @@ public static Response.ResponseBuilder getCourts( } } - public static boolean getIsIndividual( - TylerFirmFactory firmFactory, Optional tylerUser) { - Optional firmClient = setupFirmPort(firmFactory, tylerUser, true); + public static boolean getIsIndividual(TylerFirmFactory firmFactory, UserCreds userCreds) { + Optional firmClient = setupFirmPort(firmFactory, userCreds, true); boolean isIndividual = firmClient .map( @@ -156,21 +155,16 @@ public static boolean getIsIndividual( } public static Optional setupFirmPort( - TylerFirmFactory firmFactory, Optional tylerUser) { - return setupFirmPort(firmFactory, tylerUser.map(u -> u.creds()), true); + TylerFirmFactory firmFactory, UserCreds userCreds) { + return setupFirmPort(firmFactory, userCreds, true); } public static Optional setupFirmPort( - TylerFirmFactory firmFactory, - Optional creds, - boolean needsSoapHeader) { + TylerFirmFactory firmFactory, UserCreds creds, boolean needsSoapHeader) { if (needsSoapHeader) { - if (creds.isEmpty()) { - log.warn("No creds?"); - return Optional.empty(); - } return Optional.of( - firmFactory.makeFirmClient((port) -> ServiceHelpers.setupServicePort(port, creds.get()))); + firmFactory.makeFirmClient( + (port) -> ServiceHelpers.setupServicePort(port, creds.toHeaders()))); } else { return Optional.of(firmFactory.makeFirmClient(ServiceHelpers::setupServicePort)); } diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/TylerUserFromServer.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/TylerUserFromServer.java deleted file mode 100644 index 8c0e7b629..000000000 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/server/utils/TylerUserFromServer.java +++ /dev/null @@ -1,12 +0,0 @@ -package edu.suffolk.litlab.efsp.server.utils; - -import edu.suffolk.litlab.efsp.tyler.TylerUserNamePassword; -import java.security.Principal; - -public record TylerUserFromServer(TylerUserNamePassword creds) implements Principal { - // Principals can only have one name, so stick with the user name (email). - @Override - public String getName() { - return creds.getUserName(); - } -} diff --git a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/TylerCodeUpdater.java b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/TylerCodeUpdater.java index effc2ff3f..72faab02d 100644 --- a/proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/TylerCodeUpdater.java +++ b/proxyserver/src/main/java/edu/suffolk/litlab/efsp/tyler/ecfcodes/TylerCodeUpdater.java @@ -10,6 +10,7 @@ import edu.suffolk.litlab.efsp.ecfcodes.CodeUpdater; import edu.suffolk.litlab.efsp.ecfcodes.CodeUpdater.CourtCodelistInfo; import edu.suffolk.litlab.efsp.ecfcodes.CodeUrlGetter; +import edu.suffolk.litlab.efsp.server.auth.UserNamePassword; import edu.suffolk.litlab.efsp.server.ecf4.TylerEcf4Helper; import edu.suffolk.litlab.efsp.server.logging.MDCWrappers; import edu.suffolk.litlab.efsp.server.utils.HeaderSigner; @@ -20,7 +21,6 @@ import edu.suffolk.litlab.efsp.tyler.TylerClients; import edu.suffolk.litlab.efsp.tyler.TylerUserClient; import edu.suffolk.litlab.efsp.tyler.TylerUserFactory; -import edu.suffolk.litlab.efsp.tyler.TylerUserNamePassword; import jakarta.xml.bind.JAXBException; import jakarta.xml.ws.BindingProvider; import jakarta.xml.ws.soap.SOAPFaultException; @@ -64,7 +64,7 @@ private static FilingReviewMDEPort loginWithTyler( authReq.setEmail(userEmail); authReq.setPassword(userPassword); AuthenticateResponseType authRes = userPort.authenticateUser(authReq); - List
headersList = TylerUserNamePassword.makeHeaderList(authRes); + List
headersList = UserNamePassword.makeHeaderList(authRes); FilingReviewMDEPort filingPort = filingFactory.get().getFilingReviewMDEPort(); ServiceHelpers.setupServicePort((BindingProvider) filingPort); Map ctx = ((BindingProvider) filingPort).getRequestContext(); diff --git a/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/auth/SecurityHubTest.java b/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/auth/SecurityHubTest.java index 73128758c..c9c589cd1 100644 --- a/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/auth/SecurityHubTest.java +++ b/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/auth/SecurityHubTest.java @@ -154,12 +154,15 @@ public void testTylerLogin() throws Exception { } @Test - public void testLoginWithUnauthorizedJeffNet() throws Exception { + public void testLoginWithDeprecatedJeffNet() throws Exception { ObjectNode jeffNetNode = mapper.createObjectNode(); jeffNetNode.put("api_key", "the_jeffnet_key"); loginNode.set("jeffnet", jeffNetNode); Optional withJeffnet = hub.login(API_KEY, loginNode); - assertThat(withJeffnet).isEmpty(); + assertThat(withJeffnet).isPresent(); + var tokens = withJeffnet.get().getTokens(); + assertThat(tokens).containsKey("JEFFNET-TOKEN"); + assertThat(tokens.get("JEFFNET-TOKEN")).isEqualTo("deprecated"); } @Test diff --git a/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/services/AdminUserServiceTest.java b/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/services/AdminUserServiceTest.java index 901604754..57dd4099d 100644 --- a/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/services/AdminUserServiceTest.java +++ b/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/services/AdminUserServiceTest.java @@ -12,6 +12,7 @@ import edu.suffolk.litlab.efsp.db.LoginDatabase; import edu.suffolk.litlab.efsp.db.model.AtRest; import edu.suffolk.litlab.efsp.server.EfspServer; +import edu.suffolk.litlab.efsp.server.auth.SecurityHub; import edu.suffolk.litlab.efsp.tyler.TylerClients; import edu.suffolk.litlab.efsp.tyler.TylerFirmClient; import edu.suffolk.litlab.efsp.tyler.TylerFirmFactory; @@ -106,7 +107,8 @@ private void startServer() { sf.setAddress(ENDPOINT_ADDRESS); Map extensionMappings = Map.of("json", MediaType.APPLICATION_JSON); sf.setExtensionMappings(extensionMappings); - List providers = EfspServer.providers(() -> ld); + List providers = + EfspServer.providers(() -> ld, new SecurityHub(() -> ld, List.of(Jurisdiction.ILLINOIS))); sf.setProviders(providers); server = sf.create(); diff --git a/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/services/CodesServiceTest.java b/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/services/CodesServiceTest.java index 754cf0d97..24067c3fa 100644 --- a/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/services/CodesServiceTest.java +++ b/proxyserver/src/test/java/edu/suffolk/litlab/efsp/server/services/CodesServiceTest.java @@ -88,7 +88,7 @@ private void startServer() throws Exception { "xml", MediaType.APPLICATION_XML, "json", MediaType.APPLICATION_JSON); sf.setExtensionMappings(extensionMappings); - List providers = EfspServer.providers(() -> null); + List providers = EfspServer.providers(() -> null, null); sf.setProviders(providers); server = sf.create(); }