Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ private void invalidateSession(final HttpServletRequest request) {
private void doLogout(final HttpServletRequest request, final HttpServletResponse response) throws IOException {
final HttpSession session = request.getSession();
final String idToken = (String)session.getAttribute(SESSION_PARAM_ID_TOKEN);
final String redirectUri = request.getRequestURL().toString().replace("/do/logout.action", "");
final String redirectUri = UrlUtils.determineFrontendURL(request).replace("/do/logout.action", "");
session.invalidate();
response.sendRedirect(oidcService.getLogoutUrl(redirectUri, idToken));
}
Expand All @@ -224,7 +224,7 @@ private void doLogin(final HttpServletRequest request, final HttpServletResponse
final HttpSession session = request.getSession();
final String authorizationCode = request.getParameter("code");
final String stateParameter = request.getParameter("state");
final String redirectUri = request.getRequestURL().toString();
final String redirectUri = UrlUtils.determineFrontendURL(request);
final String redirectTo = request.getParameter("redirectTo");
final String error = request.getParameter("error");
final String errorDescription = request.getParameter("error_description");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import org.entando.entando.aps.util.UrlUtils;
import org.entando.entando.ent.exception.EntException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand Down Expand Up @@ -58,7 +59,7 @@ public int service(RequestContext reqCtx, int status) {
} else if (!currentUser.getUsername().equalsIgnoreCase(SystemConstants.GUEST_USER_NAME)) {
return this.returnUserNotAuthorized(reqCtx);
} else {
StringBuilder targetUrl = new StringBuilder(req.getRequestURL());
StringBuilder targetUrl = new StringBuilder(UrlUtils.determineFrontendURL(req));
targetUrl.append("?");
String queryString = req.getQueryString();
if (null != queryString && queryString.trim().length() > 0) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<DynamicMapping>
<enabled>false</enabled>
<persist>FULL</persist>
<mappings>
<mapping>
<enabled>true</enabled>
<path>groups</path>
<kind>GROUPCLAIM</kind>
</mapping>
<mapping>
<enabled>true</enabled>
<path>realm_access.roles</path>
<kind>ROLECLAIM</kind>
</mapping>
<mapping>
<enabled>false</enabled>
<path>realm_access.roles</path>
<kind>ROLEGROUPCLAIM</kind>
<separator>_SEP_</separator>
</mapping>
<mapping>
<enabled>false</enabled>
<attribute>AD_ROLE</attribute>
<kind>ROLE</kind>
</mapping>
<mapping>
<enabled>false</enabled>
<attribute>AD_GROUP</attribute>
<kind>GROUP</kind>
</mapping>
<mapping>
<enabled>false</enabled>
<attribute>AD_GROUPROLE</attribute>
<kind>ROLEGROUP</kind>
<separator>_r_</separator>
</mapping>
</mappings>
<exclusions>
<exclusion>default-roles-entando-development</exclusion>
<exclusion>offline_access</exclusion>
<exclusion>uma_authorization</exclusion>
</exclusions>
<roles>
<role>imported_role</role>
<role>imported_role2</role>
</roles>
<groups>
<group>imported_group</group>
<group>imported_group2</group>
</groups>
</DynamicMapping>
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,8 @@ public void setUp() {
Mockito.lenient().when(session.getServletContext()).thenReturn(svCtx);
Mockito.lenient().when(wac.getBean(ITenantManager.class)).thenReturn(tenantManager);
Mockito.lenient().when(request.getServerName()).thenReturn("dev.entando.org");
Mockito.lenient().when(request.getScheme()).thenReturn("https");
Mockito.lenient().when(request.getServerPort()).thenReturn(443);
Mockito.lenient().when(request.getHeader("X-Forwarded-Proto")).thenReturn("https");
Mockito.lenient().when(request.getHeader("Host")).thenReturn("dev.entando.org");
}
Expand All @@ -117,7 +119,7 @@ void testAuthenticationFlow() throws IOException, ServletException, EntException
when(request.getRequestURL()).thenReturn(new StringBuffer(loginEndpoint));
Mockito.lenient().when(request.getParameter(eq("redirectTo"))).thenReturn(requestRedirect);

final String redirect = "http://dev.entando.org/auth/realms/entando/protocol/openid-connect/auth";
final String redirect = "https://dev.entando.org/auth/realms/entando/protocol/openid-connect/auth";
when(oidcService.getRedirectUrl(any(), any(), any())).thenReturn(redirect);

keycloakFilter.doFilter(request, response, filterChain);
Expand Down Expand Up @@ -169,7 +171,6 @@ void testAuthenticationFlow() throws IOException, ServletException, EntException

@Test
void testAuthenticationFlowWithError() {
final String loginEndpoint = "https://dev.entando.org/entando-app/do/login";
final String state = "0ca97afd-f0b0-4860-820a-b7cd1414f69c";
final String authorizationCode = "the-authorization-code-from-keycloak";

Expand All @@ -185,7 +186,6 @@ void testAuthenticationFlowWithError() {
when(request.getServletPath()).thenReturn("/do/login");
when(request.getParameter(eq("code"))).thenReturn(authorizationCode);
when(request.getParameter(eq("state"))).thenReturn(state);
when(request.getRequestURL()).thenReturn(new StringBuffer(loginEndpoint));
Mockito.lenient().when(request.getContextPath()).thenReturn("/entando-app");


Expand All @@ -196,15 +196,12 @@ void testAuthenticationFlowWithError() {
Mockito.lenient().when(auth.getRefreshToken()).thenReturn("refresh-token-over-here");
try ( MockedStatic<WebApplicationContextUtils> wacUtil = Mockito.mockStatic(WebApplicationContextUtils.class)) {
wacUtil.when(() -> WebApplicationContextUtils.getWebApplicationContext(svCtx)).thenReturn(wac);
Assertions.assertThrows(EntandoTokenException.class, () -> {
keycloakFilter.doFilter(request, response, filterChain);
});
Assertions.assertThrows(EntandoTokenException.class, () -> keycloakFilter.doFilter(request, response, filterChain));
}
}

@Test
void testAuthenticationWithInvalidAuthCode() throws IOException, ServletException {
final String loginEndpoint = "https://dev.entando.org/entando-app/do/login";
final String state = "0ca97afd-f0b0-4860-820a-b7cd1414f69c";
final String authorizationCode = "the-authorization-code-from-keycloak";

Expand All @@ -216,7 +213,6 @@ void testAuthenticationWithInvalidAuthCode() throws IOException, ServletExceptio
when(request.getServletPath()).thenReturn("/do/login");
when(request.getParameter(eq("code"))).thenReturn(authorizationCode);
when(request.getParameter(eq("state"))).thenReturn(state);
when(request.getRequestURL()).thenReturn(new StringBuffer(loginEndpoint));
when(request.getContextPath()).thenReturn("/entando-app");

final HttpClientErrorException exception = Mockito.mock(HttpClientErrorException.class);
Expand All @@ -235,11 +231,9 @@ void testAuthenticationWithInvalidAuthCode() throws IOException, ServletExceptio
@Test
void shouldLoginWithInvalidRedirectURLHostnameNotThrowError() throws IOException, ServletException {
final String requestRedirect = "https://not.authorized.url";
final String loginEndpoint = "https://dev.entando.org/entando-app/do/login";

when(configuration.isEnabled()).thenReturn(true);
when(request.getServletPath()).thenReturn("/do/login");
when(request.getRequestURL()).thenReturn(new StringBuffer(loginEndpoint));
Mockito.lenient().when(request.getParameter(eq("redirectTo"))).thenReturn(requestRedirect);

final String redirect = "http://dev.entando.org/auth/realms/entando/protocol/openid-connect/auth";
Expand All @@ -254,11 +248,8 @@ void shouldLoginWithInvalidRedirectURLHostnameNotThrowError() throws IOException

@Test
void testLogout() throws IOException, ServletException {
final String loginEndpoint = "https://dev.entando.org/entando-app/do/logout.action";

when(configuration.isEnabled()).thenReturn(true);
when(request.getServletPath()).thenReturn("/do/logout.action");
when(request.getRequestURL()).thenReturn(new StringBuffer(loginEndpoint));

final String redirect = "http://dev.entando.org/auth/realms/entando/protocol/openid-connect/logout";
when(oidcService.getLogoutUrl(any(),any())).thenReturn(redirect);
Expand Down Expand Up @@ -437,11 +428,9 @@ void apiCallShouldNotSaveUserOnSession() throws Exception {
void testLoginWithAuthorizationCode() throws Exception {

final String path = "/do/login";
final String endpoint = "https://dev.entando.org/entando-app" + path;

when(configuration.isEnabled()).thenReturn(true);
when(request.getServletPath()).thenReturn(path);
when(request.getRequestURL()).thenReturn(new StringBuffer(endpoint));
when(request.getParameter("state")).thenReturn("<state>");
when(request.getParameter("code")).thenReturn("<code>");

Expand Down Expand Up @@ -593,7 +582,6 @@ void shouldLoginWithRedirectToDifferentDomainNotThrowException() throws Exceptio
String path = "/do/login.action";
when(configuration.isEnabled()).thenReturn(true);
when(request.getServletPath()).thenReturn(path);
when(request.getRequestURL()).thenReturn(new StringBuffer("http://dev.entando.org/entando-de-app/do/login.action"));
when(request.getParameter("code")).thenReturn(null);
when(request.getParameter("state")).thenReturn(null);
when(request.getParameter("redirectTo")).thenReturn("http://fakedomain.entando.org/entando-de-app/pages/en/homepage/");
Expand All @@ -616,15 +604,14 @@ void shouldLoginWithRedirectWithUrlExecuteFine() throws Exception {
final String contextRoot = "/entando-de-app";
final String protoAndServerName = "http://dev.entando.org";

testLoginExecuteFine(protoAndServerName, contextRoot, path, protoAndServerName+contextRoot+redirectPath, redirectPath);
testLoginExecuteFine(contextRoot, path, protoAndServerName+contextRoot+redirectPath, redirectPath);

}

private void testLoginExecuteFine(final String protoAndServerName, final String contextRoot, final String path,
private void testLoginExecuteFine(final String contextRoot, final String path,
final String redirectToUri, final String redirectToPath) throws Exception {
when(configuration.isEnabled()).thenReturn(true);
when(request.getServletPath()).thenReturn(path);
when(request.getRequestURL()).thenReturn(new StringBuffer(protoAndServerName+contextRoot+path));
when(request.getParameter("code")).thenReturn(null);
when(request.getParameter("state")).thenReturn(null);
when(request.getParameter("redirectTo")).thenReturn(redirectToUri);
Expand All @@ -649,10 +636,8 @@ void shouldLoginWithRedirectToWithPathExecuteFine() throws Exception {
final String path = "/do/login.action";
final String redirectPath = "/pages/en/homepage/";
final String contextRoot = "/entando-de-app";
final String protoAndServerName = "http://dev.entando.org";

testLoginExecuteFine(protoAndServerName, contextRoot, path, contextRoot+redirectPath, redirectPath);

testLoginExecuteFine(contextRoot, path, contextRoot+redirectPath, redirectPath);
}

@Test
Expand All @@ -661,7 +646,6 @@ void shouldLoginWithRedirectToSameDomainWithDifferentSchemaExecuteFine() throws
String path = "/do/login.action";
when(configuration.isEnabled()).thenReturn(true);
when(request.getServletPath()).thenReturn(path);
when(request.getRequestURL()).thenReturn(new StringBuffer("http://dev.entando.org/entando-de-app/do/login.action"));
when(request.getParameter("code")).thenReturn(null);
when(request.getParameter("state")).thenReturn(null);
when(request.getParameter("redirectTo")).thenReturn("https://dev.entando.org/entando-de-app/pages/en/mypage");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ private String validatedParameter(String name) {
try {
value = ESAPI.validator().getValidInput("HTTP parameter value: " + value, value, "HTTPParameterValue", 2000, true);
} catch (ValidationException e) {
log.error("Invalid parameter ('{}' - '{}'), encoding as HTML attribute", name, value, e);
log.warn("Invalid parameter ('{}' - '{}'), encoding as HTML attribute", name, value);
value = ESAPI.encoder().encodeForHTMLAttribute(value);
} catch (Throwable e) {
log.debug("Invalid parameter ('{}' - '{}') - error message {}", name, value, e.getMessage());
Expand All @@ -78,7 +78,7 @@ private String validatedHeader(String name) {
try {
value = ESAPI.validator().getValidInput("HTTP header value: " + value, value, "HTTPHeaderValue", 150, false);
} catch (ValidationException e) {
log.error("Invalid header ('{}' - '{}'), encoding as HTML attribute", name, value, e);
log.warn("Invalid header ('{}' - '{}'), encoding as HTML attribute", name, value);
value = ESAPI.encoder().encodeForHTMLAttribute(value);
} catch (Throwable e) {
log.debug("Invalid header ('{}' - '{}') - error message {}", name, value, e.getMessage());
Expand Down
4 changes: 2 additions & 2 deletions portal-ui/src/main/resources/ESAPI.properties
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ Logger.MaxLogFileSize=10000000
# You can also disable intrusion detection completely by changing
# the following parameter to true
#
IntrusionDetector.Disable=false
IntrusionDetector.Disable=true
#
IntrusionDetector.event.test.count=2
IntrusionDetector.event.test.interval=10
Expand Down Expand Up @@ -444,7 +444,7 @@ Validator.Redirect=^\\/test.*$
Validator.HTTPScheme=^(http|https)$
Validator.HTTPServerName=^[a-zA-Z0-9_.\\-]*$
Validator.HTTPParameterName=^[a-zA-Z0-9_]{1,32}$
Validator.HTTPParameterValue=^[a-zA-Z0-9.\\-\\/+=@_ ]*$
Validator.HTTPParameterValue=^[\\p{L}0-9.\\-\\/+=@_ ]*$
Validator.HTTPCookieName=^[a-zA-Z0-9\\-_]{1,32}$
Validator.HTTPCookieValue=^[a-zA-Z0-9\\-\\/+=_ ]*$
# Note that max header name capped at 150 in SecurityRequestWrapper!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.response.FacetField;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrException;
Expand Down Expand Up @@ -404,8 +405,8 @@ private Query createRangeQuery(SearchEngineFilter<?> filter, String key, String
Long upperValue = (null != filter.getEnd()) ? ((Number) filter.getEnd()).longValue() : Long.MAX_VALUE;
query = LongPoint.newRangeQuery(key, lowerValue, upperValue);
} else {
String start = (null != filter.getStart()) ? filter.getStart().toString().toLowerCase() : "A";
String end = (null != filter.getEnd()) ? filter.getEnd().toString().toLowerCase() + "z" : null;
String start = (null != filter.getStart()) ? ClientUtils.escapeQueryChars(filter.getStart().toString().toLowerCase()) : "A";
String end = (null != filter.getEnd()) ? ClientUtils.escapeQueryChars(filter.getEnd().toString().toLowerCase()) + "z" : null;
query = TermRangeQuery.newStringRange(key, start + relevance, (null != end) ? (end + relevance) : null,
true, true);
}
Expand Down Expand Up @@ -479,7 +480,7 @@ private Query createSingleValueQueryNotExact(SearchEngineFilter<?> filter, Strin
compositeQuery.add(queryTerm, BooleanClause.Occur.SHOULD);
String attachmentKey = key + SolrFields.ATTACHMENT_FIELD_SUFFIX;
TermQuery termAttachment = new TermQuery(
new Term(attachmentKey, val.toLowerCase() + relevance));
new Term(attachmentKey, ClientUtils.escapeQueryChars(val.toLowerCase()) + relevance));
compositeQuery.add(termAttachment, BooleanClause.Occur.SHOULD);
fieldQuery.add(compositeQuery.build(), bc);
} else {
Expand Down Expand Up @@ -520,11 +521,19 @@ protected Query getTermQueryForTextSearch(String key, String value, boolean isLi
//NOTE: search for lower case....
String stringValue = value.toLowerCase();
boolean useWildCard = false;
if (value.startsWith("*") || value.endsWith("*")) {
boolean leadingStar = stringValue.startsWith("*");
boolean trailingStar = stringValue.endsWith("*");
if (leadingStar || trailingStar) {
useWildCard = true;
int from = leadingStar ? 1 : 0;
int to = (trailingStar && stringValue.length() > from) ? stringValue.length() - 1 : stringValue.length();
String core = stringValue.substring(from, to);
stringValue = (leadingStar ? "*" : "") + ClientUtils.escapeQueryChars(core) + (trailingStar ? "*" : "");
} else if (isLikeSearch) {
stringValue = "*" + stringValue + "*";
stringValue = "*" + ClientUtils.escapeQueryChars(stringValue) + "*";
useWildCard = true;
} else {
stringValue = ClientUtils.escapeQueryChars(stringValue);
}
Term term = new Term(key, stringValue + relevance);
return (useWildCard) ? new WildcardQuery(term) : new TermQuery(term);
Expand Down
Loading
Loading