This is an automated email from the ASF dual-hosted git repository.
abernal pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git
The following commit(s) were added to refs/heads/master by this push:
new 041cd532b JSPWIKI-1056: Enhance Absolute URL Utility Methods in
HttpUtil
new 0cf7a0429 Merge pull request #311 from arturobernalg/JSPWIKI-1056
041cd532b is described below
commit 041cd532b56b78bcc080b2ef7404ef8eda246548
Author: Arturo Bernal <[email protected]>
AuthorDate: Mon Oct 2 21:19:24 2023 +0200
JSPWIKI-1056: Enhance Absolute URL Utility Methods in HttpUtil
- Implement getAbsoluteUrl methods in HttpUtil to construct absolute URLs,
considering various headers like X-Forwarded-Host, X-Forwarded-Proto, and
X-Forwarded-Server.
- This enhancement allows emails to now include absolute URLs for the login
page, replacing the previous relative URLs.
---
ChangeLog.md | 7 ++
.../src/main/java/org/apache/wiki/api/Release.java | 2 +-
.../wiki/tasks/auth/SaveUserProfileTask.java | 6 +-
.../main/java/org/apache/wiki/util/HttpUtil.java | 60 ++++++++++
.../main/java/org/apache/wiki/util/URIScheme.java | 56 ++++++++++
.../java/org/apache/wiki/util/HttpUtilTest.java | 121 ++++++++++++++++++++-
6 files changed, 248 insertions(+), 4 deletions(-)
diff --git a/ChangeLog.md b/ChangeLog.md
index b35b0f975..4d3099f88 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -17,6 +17,13 @@ specific language governing permissions and limitations
under the License.
-->
+**2023-10-02 Arturo Bernal (abernal AT apache DOT org)**
+
+* _2.12.2-git-05_
+
+* [JSPWIKI-1056](https://issues.apache.org/jira/browse/JSPWIKI-1056) - URL in
registration mail is relative while it should be absolute.
+
+
**2023-10-02 Juan Pablo Santos (juanpablo AT apache DOT org)**
* _2.12.2-git-04_
diff --git a/jspwiki-api/src/main/java/org/apache/wiki/api/Release.java
b/jspwiki-api/src/main/java/org/apache/wiki/api/Release.java
index 5345f4a32..6b9594465 100644
--- a/jspwiki-api/src/main/java/org/apache/wiki/api/Release.java
+++ b/jspwiki-api/src/main/java/org/apache/wiki/api/Release.java
@@ -69,7 +69,7 @@ public final class Release {
* <p>
* If the build identifier is empty, it is not added.
*/
- public static final String BUILD = "04";
+ public static final String BUILD = "05";
/**
* This is the generic version string you should use when printing out
the version. It is of
diff --git
a/jspwiki-main/src/main/java/org/apache/wiki/tasks/auth/SaveUserProfileTask.java
b/jspwiki-main/src/main/java/org/apache/wiki/tasks/auth/SaveUserProfileTask.java
index 17fa58ecc..7893ebdc5 100644
---
a/jspwiki-main/src/main/java/org/apache/wiki/tasks/auth/SaveUserProfileTask.java
+++
b/jspwiki-main/src/main/java/org/apache/wiki/tasks/auth/SaveUserProfileTask.java
@@ -27,6 +27,7 @@ import org.apache.wiki.auth.UserManager;
import org.apache.wiki.auth.user.UserProfile;
import org.apache.wiki.i18n.InternationalizationManager;
import org.apache.wiki.tasks.TasksManager;
+import org.apache.wiki.util.HttpUtil;
import org.apache.wiki.util.MailUtil;
import org.apache.wiki.workflow.Outcome;
import org.apache.wiki.workflow.Task;
@@ -78,12 +79,15 @@ public class SaveUserProfileTask extends Task {
"notification.createUserProfile.accept.subject", app );
final String loginUrl = context.getEngine().getURL(
ContextEnum.WIKI_LOGIN.getRequestContext(), null, null );
+
+ final String absoluteLoginUrl =
HttpUtil.getAbsoluteUrl(context.getHttpRequest(), loginUrl);
+
final String content = i18n.get(
InternationalizationManager.DEF_TEMPLATE, m_loc,
"notification.createUserProfile.accept.content", app,
profile.getLoginName(),
profile.getFullname(),
profile.getEmail(),
- loginUrl );
+ absoluteLoginUrl );
MailUtil.sendMessage( context.getEngine().getWikiProperties(),
to, subject, content );
} catch ( final AddressException e) {
LOG.debug( e.getMessage(), e );
diff --git a/jspwiki-util/src/main/java/org/apache/wiki/util/HttpUtil.java
b/jspwiki-util/src/main/java/org/apache/wiki/util/HttpUtil.java
index ad956f162..33e089329 100644
--- a/jspwiki-util/src/main/java/org/apache/wiki/util/HttpUtil.java
+++ b/jspwiki-util/src/main/java/org/apache/wiki/util/HttpUtil.java
@@ -261,4 +261,64 @@ public final class HttpUtil {
response.addCookie( cookie );
}
+ /**
+ * Generates an absolute URL based on the given HttpServletRequest and a
relative URL.
+ * This method takes into account various headers like X-Forwarded-Host,
X-Forwarded-Proto,
+ * and X-Forwarded-Server to construct the absolute URL.
+ *
+ * @param request The HttpServletRequest object, used to obtain scheme,
server name, and port.
+ * @param relativeUrl The relative URL to be appended to the base URL. Can
be null.
+ * @return The absolute URL as a String.
+ * @since 2.12.2
+ */
+ public static String getAbsoluteUrl(final HttpServletRequest request,
final String relativeUrl) {
+ StringBuilder baseUrl = new StringBuilder();
+
+ // Check for proxy headers
+ final String forwardedHost = request.getHeader("X-Forwarded-Host");
+ final String forwardedProto = request.getHeader("X-Forwarded-Proto");
+ final String forwardedServer = request.getHeader("X-Forwarded-Server");
+
+ if (forwardedHost != null && forwardedProto != null) {
+ baseUrl.append(forwardedProto).append("://").append(forwardedHost);
+ } else if (forwardedServer != null && forwardedProto != null) {
+
baseUrl.append(forwardedProto).append("://").append(forwardedServer);
+ } else {
+ // Fallback to HttpServletRequest
+ final String scheme = request.getScheme();
+ final String serverName = request.getServerName();
+ final int port = request.getServerPort();
+
+ baseUrl.append(scheme).append("://").append(serverName);
+
+ // Include port only if it's not the default port for the scheme
+ if ((URIScheme.HTTP.same(scheme) && port != 80)
+ || (URIScheme.HTTPS.same(scheme) && port != 443)) {
+ baseUrl.append(':');
+ baseUrl.append(port);
+ }
+ }
+
+ if (relativeUrl != null) {
+ baseUrl.append(relativeUrl);
+ }
+
+ return baseUrl.toString();
+ }
+
+
+ /**
+ * Generate an absolute URL based solely on the given HttpServletRequest.
+ * This is a convenience method that calls {@link
#getAbsoluteUrl(HttpServletRequest, String)}
+ * with a null relative URL.
+ *
+ * @param request The HttpServletRequest object, used to obtain scheme,
server name, and port.
+ * @return The absolute URL as a String.
+ * @see #getAbsoluteUrl(HttpServletRequest, String)
+ * @since 2.12.2
+ */
+ public static String getAbsoluteUrl(final HttpServletRequest request) {
+ return getAbsoluteUrl(request, null);
+ }
+
}
diff --git a/jspwiki-util/src/main/java/org/apache/wiki/util/URIScheme.java
b/jspwiki-util/src/main/java/org/apache/wiki/util/URIScheme.java
new file mode 100644
index 000000000..e19e5dbea
--- /dev/null
+++ b/jspwiki-util/src/main/java/org/apache/wiki/util/URIScheme.java
@@ -0,0 +1,56 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+package org.apache.wiki.util;
+
+
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * Enumerates supported URI schemes.
+ *
+ */
+public enum URIScheme {
+
+ HTTP("http"), HTTPS("https");
+
+ public final String id;
+
+ URIScheme(final String id) {
+ if( StringUtils.isNotBlank( id ) ) {
+ this.id = id;
+ } else {
+ throw new IllegalArgumentException("id must not be blank");
+ }
+ }
+
+ public String getId() {
+ return id;
+ }
+
+ public boolean same(final String scheme) {
+ return id.equalsIgnoreCase(scheme);
+ }
+
+ @Override
+ public String toString() {
+ return id;
+ }
+
+}
diff --git a/jspwiki-util/src/test/java/org/apache/wiki/util/HttpUtilTest.java
b/jspwiki-util/src/test/java/org/apache/wiki/util/HttpUtilTest.java
index 1afc63e1d..c96d9728a 100644
--- a/jspwiki-util/src/test/java/org/apache/wiki/util/HttpUtilTest.java
+++ b/jspwiki-util/src/test/java/org/apache/wiki/util/HttpUtilTest.java
@@ -23,6 +23,11 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
public class HttpUtilTest {
@@ -59,11 +64,123 @@ public class HttpUtilTest {
final MockHttpServletRequest req = new MockHttpServletRequest(
"/wiki", "/example" );
req.setCookies( cookies );
- Assertions.assertEquals( "value1", HttpUtil.retrieveCookieValue( req,
"cookie1" ) );
- Assertions.assertEquals( "value2", HttpUtil.retrieveCookieValue( req,
"cookie2" ) );
+ assertEquals( "value1", HttpUtil.retrieveCookieValue( req, "cookie1" )
);
+ assertEquals( "value2", HttpUtil.retrieveCookieValue( req, "cookie2" )
);
Assertions.assertNull( HttpUtil.retrieveCookieValue( req, "cookie3" )
);
Assertions.assertNull( HttpUtil.retrieveCookieValue( req, "cookie4" )
);
Assertions.assertNull( HttpUtil.retrieveCookieValue( req, "cookie5" )
);
}
+ @Test
+ public void testGetAbsoluteUrlWithRelativeUrl() {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getScheme()).thenReturn("http");
+ when(request.getServerName()).thenReturn("localhost");
+ when(request.getServerPort()).thenReturn(8080);
+
+ String relativeUrl = "/login";
+ String expected = "http://localhost:8080/login";
+
+ String actual = HttpUtil.getAbsoluteUrl(request, relativeUrl);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testGetAbsoluteUrlWithoutRelativeUrl() {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getScheme()).thenReturn("https");
+ when(request.getServerName()).thenReturn("localhost");
+ when(request.getServerPort()).thenReturn(443);
+
+ String expected = "https://localhost";
+
+ String actual = HttpUtil.getAbsoluteUrl(request);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testGetAbsoluteUrlWithDefaultHttpPort() {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getScheme()).thenReturn("http");
+ when(request.getServerName()).thenReturn("localhost");
+ when(request.getServerPort()).thenReturn(80);
+
+ String relativeUrl = "/login";
+ String expected = "http://localhost/login";
+
+ String actual = HttpUtil.getAbsoluteUrl(request, relativeUrl);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testGetAbsoluteUrlWithDefaultHttpsPort() {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getScheme()).thenReturn("https");
+ when(request.getServerName()).thenReturn("localhost");
+ when(request.getServerPort()).thenReturn(443);
+
+ String relativeUrl = "/login";
+ String expected = "https://localhost/login";
+
+ String actual = HttpUtil.getAbsoluteUrl(request, relativeUrl);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testGetAbsoluteUrlWithForwardedHostAndProto() {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getHeader("X-Forwarded-Host")).thenReturn("proxyhost");
+ when(request.getHeader("X-Forwarded-Proto")).thenReturn("https");
+
+ String relativeUrl = "/login";
+ String expected = "https://proxyhost/login";
+
+ String actual = HttpUtil.getAbsoluteUrl(request, relativeUrl);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testGetAbsoluteUrlWithForwardedServerAndProto() {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+
when(request.getHeader("X-Forwarded-Server")).thenReturn("proxyserver");
+ when(request.getHeader("X-Forwarded-Proto")).thenReturn("https");
+
+ String relativeUrl = "/login";
+ String expected = "https://proxyserver/login";
+
+ String actual = HttpUtil.getAbsoluteUrl(request, relativeUrl);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testGetAbsoluteUrlWithNoForwardedHeaders() {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+ when(request.getScheme()).thenReturn("http");
+ when(request.getServerName()).thenReturn("localhost");
+ when(request.getServerPort()).thenReturn(8080);
+
+ String relativeUrl = "/login";
+ String expected = "http://localhost:8080/login";
+
+ String actual = HttpUtil.getAbsoluteUrl(request, relativeUrl);
+ assertEquals(expected, actual);
+ }
+
+ @Test
+ public void testGetAbsoluteUrlWithAllHeaders() {
+ HttpServletRequest request = mock(HttpServletRequest.class);
+
when(request.getHeader("X-Forwarded-Host")).thenReturn("forwardedHost");
+
when(request.getHeader("X-Forwarded-Proto")).thenReturn("forwardedProto");
+
when(request.getHeader("X-Forwarded-Server")).thenReturn("forwardedServer");
+ when(request.getScheme()).thenReturn("https");
+ when(request.getServerName()).thenReturn("localhost");
+ when(request.getServerPort()).thenReturn(443);
+
+ String expected = "forwardedProto://forwardedHost";
+
+ String actual = HttpUtil.getAbsoluteUrl(request);
+ assertEquals(expected, actual);
+ }
+
+
}