diff --git a/Model/lib/conifer/roles/conifer/templates/WDK/tomcat_context.xml.j2 b/Model/lib/conifer/roles/conifer/templates/WDK/tomcat_context.xml.j2 index 90d94a07a..6429616c2 100644 --- a/Model/lib/conifer/roles/conifer/templates/WDK/tomcat_context.xml.j2 +++ b/Model/lib/conifer/roles/conifer/templates/WDK/tomcat_context.xml.j2 @@ -14,7 +14,7 @@ site_vars file: {{ site_vars }} docBase="{{ contextxml_docBase }}" privileged="{{ contextxml_privileged|default("false") }}" swallowOutput="{{ contextxml_swallowOutput|default("true") }}" - allowLinking="{{ contextxml_allowLinking|default("true") }}" > + diff --git a/Model/lib/rng/wdkModel-config.rng b/Model/lib/rng/wdkModel-config.rng index ea400562e..d95300399 100644 --- a/Model/lib/rng/wdkModel-config.rng +++ b/Model/lib/rng/wdkModel-config.rng @@ -70,6 +70,9 @@ + + + diff --git a/Model/pom.xml b/Model/pom.xml index 847794e4b..2d79536b7 100644 --- a/Model/pom.xml +++ b/Model/pom.xml @@ -147,7 +147,7 @@ javax.servlet - servlet-api + javax.servlet-api provided diff --git a/Model/src/main/java/org/gusdb/wdk/controller/filter/HttpResponseHeaderLogger.java b/Model/src/main/java/org/gusdb/wdk/controller/filter/HttpResponseHeaderLogger.java index ea2dd06a0..4601079b7 100644 --- a/Model/src/main/java/org/gusdb/wdk/controller/filter/HttpResponseHeaderLogger.java +++ b/Model/src/main/java/org/gusdb/wdk/controller/filter/HttpResponseHeaderLogger.java @@ -139,6 +139,7 @@ public void setStatus(int sc) { super.setStatus(sc); } + @Deprecated @Override public void setStatus(int sc, String sm) { _responseStatus = sc; diff --git a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfig.java b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfig.java index a25a4c18c..dffb4d944 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfig.java +++ b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfig.java @@ -149,6 +149,7 @@ public String getName() { */ private final AuthenticationMethod _authenticationMethod; private final String _oauthUrl; // needed if method is OAUTH2 + private final String _externalOauthUrl; // may be needed if method is OAUTH2 and internal URL is not available externally private final String _oauthClientId; // needed if method is OAUTH2 private final String _oauthClientSecret; // needed if method is OAUTH2 private final String _changePasswordUrl; // probably needed if method is OAUTH2 @@ -170,7 +171,7 @@ public ModelConfig(String modelName, String projectId, Path gusHome, boolean cac List adminEmails, String emailSubject, String emailContent, ModelConfigUserDB userDB, ModelConfigAppDB appDB, ModelConfigUserDatasetStore userDatasetStoreConfig, QueryMonitor queryMonitor, boolean monitorBlockedThreads, int blockedThreshold, AuthenticationMethod authenticationMethod, - String oauthUrl, String oauthClientId, String oauthClientSecret, String changePasswordUrl, + String oauthUrl, String externalOauthUrl, String oauthClientId, String oauthClientSecret, String changePasswordUrl, String keyStoreFile, String keyStorePassPhrase) { // basic model information @@ -221,6 +222,7 @@ public ModelConfig(String modelName, String projectId, Path gusHome, boolean cac // user authentication setup _authenticationMethod = authenticationMethod; _oauthUrl = oauthUrl; + _externalOauthUrl = externalOauthUrl; _oauthClientId = oauthClientId; _oauthClientSecret = oauthClientSecret; _changePasswordUrl = changePasswordUrl; @@ -382,6 +384,14 @@ public String getOauthUrl() { return _oauthUrl; } + /** + * @return base URL of OAuth2 server to use for authentication + * (called only if authentication method is OAUTH2) + */ + public String getExternalOauthUrl() { + return _externalOauthUrl != null && !_externalOauthUrl.isBlank() ? _externalOauthUrl : _oauthUrl; + } + /** * @return OAuth2 client ID to use for authentication * (called only if authentication method is OAUTH2) diff --git a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigBuilder.java b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigBuilder.java index e9d93f467..bb54fd2d9 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigBuilder.java +++ b/Model/src/main/java/org/gusdb/wdk/model/config/ModelConfigBuilder.java @@ -65,6 +65,7 @@ public class ModelConfigBuilder { // user authentication setup private AuthenticationMethod _authenticationMethod = AuthenticationMethod.USER_DB; private String _oauthUrl = ""; // needed if method is OAUTH2 + private String _externalOauthUrl = null; // may be needed if method is OAUTH2 and internal URL is not available externally private String _oauthClientId = ""; // needed if method is OAUTH2 private String _oauthClientSecret = ""; // needed if method is OAUTH2 private String _changePasswordUrl = ""; // probably needed if method is OAUTH2 @@ -152,6 +153,7 @@ public ModelConfig build() throws WdkModelException { // user authentication setup _authenticationMethod, _oauthUrl, + _externalOauthUrl, _oauthClientId, _oauthClientSecret, _changePasswordUrl, @@ -308,6 +310,17 @@ public void setOauthUrl(String oauthUrl) { _oauthUrl = oauthUrl; } + /** + * @param externalOauthUrl base URL of OAuth2 server to use for authentication + * (used only if authentication method is OAUTH2). This may differ from the + * (internal) oauthUrl for some deployments. The external value is returned to + * external clients, telling them how to connect to OAuth. The internal value + * is what WDK actually uses to connect directly to OAuth. + */ + public void setExternalOauthUrl(String externalOauthUrl) { + _externalOauthUrl = externalOauthUrl; + } + /** * @param oauthClientId OAuth2 client ID to use for authentication * (used only if authentication method is OAUTH2) diff --git a/Model/src/main/java/org/gusdb/wdk/model/user/UserReferenceFactory.java b/Model/src/main/java/org/gusdb/wdk/model/user/UserReferenceFactory.java index 2cc0cfbd1..0ac77a7b1 100644 --- a/Model/src/main/java/org/gusdb/wdk/model/user/UserReferenceFactory.java +++ b/Model/src/main/java/org/gusdb/wdk/model/user/UserReferenceFactory.java @@ -37,8 +37,8 @@ class UserReferenceFactory { // SQL and types to select user ref by ID private static final String SELECT_USER_REF_BY_ID_SQL = "select " + COL_USER_ID + ", " + COL_IS_GUEST + ", " + COL_FIRST_ACCESS + - " from " + USER_SCHEMA_MACRO + TABLE_USERS + - " where " + COL_USER_ID + " = ?"; + " from " + USER_SCHEMA_MACRO + TABLE_USERS + + " where " + COL_USER_ID + " = ?"; private static final Integer[] SELECT_USER_REF_BY_ID_PARAM_TYPES = { Types.BIGINT }; @@ -67,7 +67,7 @@ public UserReferenceFactory(WdkModel wdkModel) { * changed by this code. * * @param user user to add - * @throws WdkModelException + * @throws WdkModelException */ public int addUserReference(UserInfo user) throws WdkModelException { try { @@ -104,8 +104,8 @@ public Optional getUserReference(long userId) throws WdkModelExce SELECT_USER_REF_BY_ID_PARAM_TYPES, rs -> !rs.next() - ? Optional.empty() - : Optional.of(new UserReference( + ? Optional.empty() + : Optional.of(new UserReference( rs.getLong(COL_USER_ID), rs.getBoolean(COL_IS_GUEST), new Date(rs.getTimestamp(COL_FIRST_ACCESS).getTime())))); diff --git a/Service/pom.xml b/Service/pom.xml index 85c1b2a16..29741ebc5 100644 --- a/Service/pom.xml +++ b/Service/pom.xml @@ -113,7 +113,7 @@ javax.servlet - servlet-api + javax.servlet-api provided diff --git a/Service/src/main/java/org/gusdb/wdk/service/formatter/ProjectFormatter.java b/Service/src/main/java/org/gusdb/wdk/service/formatter/ProjectFormatter.java index deaa0ee20..8cd0cb525 100644 --- a/Service/src/main/java/org/gusdb/wdk/service/formatter/ProjectFormatter.java +++ b/Service/src/main/java/org/gusdb/wdk/service/formatter/ProjectFormatter.java @@ -44,8 +44,10 @@ public static JSONObject getWdkProjectInfo(WdkModel wdkModel, String serviceEndp // create authentication config sub-object JSONObject authConfig = new JSONObject() .put(JsonKeys.AUTHENTICATION_METHOD, config.getAuthenticationMethodEnum().name()) - .put(JsonKeys.OAUTH_URL, config.getOauthUrl()) - .put(JsonKeys.OAUTH_CLIENT_URL, serviceEndpoint) + // Tell client to use external URL + .put(JsonKeys.OAUTH_URL, config.getExternalOauthUrl()) + // Always use HTTPS + .put(JsonKeys.OAUTH_CLIENT_URL, serviceEndpoint.replace("http://","https://")) .put(JsonKeys.OAUTH_CLIENT_ID, config.getOauthClientId()); // create profile property config sub-array diff --git a/Service/src/main/java/org/gusdb/wdk/service/service/SessionService.java b/Service/src/main/java/org/gusdb/wdk/service/service/SessionService.java index 4e8f3b3c3..e2da20cec 100644 --- a/Service/src/main/java/org/gusdb/wdk/service/service/SessionService.java +++ b/Service/src/main/java/org/gusdb/wdk/service/service/SessionService.java @@ -283,9 +283,12 @@ public Response processLogout() throws WdkModelException { User oldUser = getRequestingUser(); getTemporaryUserData().invalidate(); + // build context URI that always uses https + String contextUri = getRequest().getNoContextUri().replace("http://", "https://"); + // if user is already a guest, no need to log out if (oldUser.isGuest()) - return createRedirectResponse(getContextUri()).build(); + return createRedirectResponse(contextUri).build(); // get a new session and add new guest user to it TwoTuple newUser = getWdkModel().getUserFactory().createUnregisteredUser(); @@ -299,7 +302,7 @@ public Response processLogout() throws WdkModelException { logoutCookies.add(extraCookie); } - ResponseBuilder builder = createRedirectResponse(getContextUri()); + ResponseBuilder builder = createRedirectResponse(contextUri); for (CookieBuilder logoutCookie : logoutCookies) { builder.cookie(logoutCookie.toJaxRsCookie()); } @@ -342,7 +345,7 @@ private static ResponseBuilder createJsonResponse(boolean success, String messag */ private static ResponseBuilder createRedirectResponse(String redirectUrl) throws WdkModelException { try { - return Response.temporaryRedirect(new URI(redirectUrl)); + return Response.temporaryRedirect(new URI(redirectUrl.replace("http://","https://"))); } catch (URISyntaxException e) { throw new WdkModelException("Redirect " + redirectUrl + " not a valid URI.");