Revise Share token exchange handling

- retry if refresh of exchanged token yields invalid token (wrong
  audience - known case of apparently incorrect Keycloak behaviour)
- use custom header instead of redirect patch to have Repository tier not
  redirect to Keycloak login page on unauthenticated access from Share
- activate audience verification which is inactive with Keycloak class
  defaults
This commit is contained in:
AFaust
2020-06-05 14:52:15 +02:00
parent 399419068f
commit 4096f741a5
9 changed files with 110 additions and 37 deletions

View File

@@ -133,6 +133,7 @@
<property name="handlePublicApi" value="${keycloak.authentication.sso.handlePublicApi}" />
<property name="loginPageUrl" value="${keycloak.authentication.loginPageUrl}" />
<property name="originalRequestUrlHeaderName" value="${keycloak.authentication.sso.originalRequestUrlHeaderName}" />
<property name="noKeycloakHandlingHeaderName" value="x-${moduleId}-no-keycloak-handling" />
<property name="bodyBufferLimit" value="${keycloak.authentication.bodyBufferLimit}" />
<property name="sslRedirectPort" value="${keycloak.authentication.sslRedirectPort}" />
<property name="keycloakDeployment" ref="keycloakDeployment" />

View File

@@ -19,7 +19,7 @@ keycloak.authentication.sslRedirectPort=8443
keycloak.authentication.bodyBufferLimit=10485760
# override for a direct route to the auth server host
# useful primarily for Dockerized deployments where container running Alfresco cannot resolve the auth server via the public DNS name
# useful primarily for Docker-ized deployments where container running Alfresco cannot resolve the auth server via the public DNS name
keycloak.authentication.directAuthHost=
keycloak.adapter.auth-server-url=http://localhost:8180/auth
@@ -29,6 +29,8 @@ keycloak.adapter.ssl-required=none
keycloak.adapter.public-client=false
keycloak.adapter.credentials.provider=secret
keycloak.adapter.credentials.secret=
# for some reason, this is not a sane default in Keycloak Adapter config
keycloak.adapter.verify-token-audience=true
# TODO default settings (identical to AdapterConfig defaults) to better align with default Alfresco subsystem property handling

View File

@@ -116,6 +116,8 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter
protected String originalRequestUrlHeaderName;
protected String noKeycloakHandlingHeaderName;
protected int bodyBufferLimit = DEFAULT_BODY_BUFFER_LIMIT;
// use 8443 as default SSL redirect based on Tomcat default server.xml configuration
@@ -146,6 +148,8 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter
PropertyCheck.mandatory(this, "keycloakTicketTokenCache", this.keycloakTicketTokenCache);
PropertyCheck.mandatory(this, "publicApiRuntimeContainer", this.publicApiRuntimeContainer);
PropertyCheck.mandatory(this, "noKeycloakHandlingHeaderName", this.noKeycloakHandlingHeaderName);
// parent class does not check, so we do
PropertyCheck.mandatory(this, "authenticationService", this.authenticationService);
PropertyCheck.mandatory(this, "authenticationComponent", this.authenticationComponent);
@@ -222,6 +226,15 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter
this.originalRequestUrlHeaderName = originalRequestUrlHeaderName;
}
/**
* @param noKeycloakHandlingHeaderName
* the noKeycloakHandlingHeaderName to set
*/
public void setNoKeycloakHandlingHeaderName(final String noKeycloakHandlingHeaderName)
{
this.noKeycloakHandlingHeaderName = noKeycloakHandlingHeaderName;
}
/**
* @param bodyBufferLimit
* the bodyBufferLimit to set
@@ -710,6 +723,7 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter
boolean skip = false;
final String authHeader = req.getHeader(HEADER_AUTHORIZATION);
final String noKeycloakLoginRedirectHeader = req.getHeader(this.noKeycloakHandlingHeaderName);
final String servletPath = req.getServletPath();
final String pathInfo = req.getPathInfo();
@@ -765,8 +779,7 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter
// cannot rely on session.isNew() to determine if this is a fresh login
// consider "fresh" login if issued within age limit (implicitly include any token refreshes performed client-side)
final boolean isFreshLogin = accessToken.getIssuedAt()
* 1000l > (System.currentTimeMillis() - FRESH_TOKEN_AGE_LIMIT_MS);
final boolean isFreshLogin = accessToken.getIat() * 1000l > (System.currentTimeMillis() - FRESH_TOKEN_AGE_LIMIT_MS);
this.keycloakAuthenticationComponent.handleUserTokens(accessToken, accessToken, isFreshLogin);
// sessionUser should be guaranteed here, but still check - we need it for the cache key
@@ -857,9 +870,9 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter
"Skipping processKeycloakAuthenticationAndActions as request is aimed at a Public v1 ReST API which does not require authentication");
skip = true;
}
// check no-auth flag (derived e.g. from checking if target web script requires authentication) only after all
// pre-emptive auth
// request details have been checked
// check no-auth flag (derived e.g. from checking if target web script requires authentication) as last resort to see if
// we need to force authentication after invalidating session
else if (Boolean.TRUE.equals(req.getAttribute(NO_AUTH_REQUIRED)))
{
LOGGER.trace(
@@ -895,6 +908,13 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter
"Skipping processKeycloakAuthenticationAndActions as filter higher up in chain determined authentication as not required");
skip = true;
}
else if (Boolean.parseBoolean(noKeycloakLoginRedirectHeader))
{
LOGGER.trace(
"Skipping processKeycloakAuthenticationAndActions as client provided custom 'no Keycloak handling' header {} with value that resolves to 'true'",
this.noKeycloakHandlingHeaderName);
skip = true;
}
// TODO Check for login page URL (rarely configured since Repository by default has no login page since 5.0)
return skip;