diff --git a/README.md b/README.md
index 34d4c99..059cf69 100644
--- a/README.md
+++ b/README.md
@@ -37,6 +37,8 @@ The Share sub-module provides a Keycloak-based filter and customisations that su
- Share logout action triggering a Keycloak logout (logging user out of other applications handled by Keycloak if those support Keycloak back-channel logout requests)
- [RFC 8693 OAuth 2.0 Token Exchange](https://tools.ietf.org/html/rfc8693) (a [preview functionality in Keycloak](https://www.keycloak.org/docs/latest/securing_apps/#_token-exchange) to properly delegate the Share-tier authentication to the Repository, if signed on via Keycloak SSO
+All authentication functionality of this addon is based on OpenID Connect. Though Keycloak does support SAML clients, no support was implemented to have Alfresco act as a SAML client against Keycloak as an alternative to OpenID Connect client behaviour.
+
# Configuration
The configuration of both the Keycloak server and this module offer a large number of properties to adjust, and various modes of operation. Therefore, the following sub-documents have been created to provide details and guides:
@@ -44,7 +46,7 @@ The configuration of both the Keycloak server and this module offer a large numb
- [Getting Started (Simple Configuration)](./docs/Simple-Configuration.md)
- Repository Configuration Reference
- [Keycloak Subsystem](./docs/Reference-Repository-Subsystem.md)
- - [Keycloak Adapter](./docs/Reference-Repository-Adapter.md)
+ - [Keycloak Adapter](./docs/Reference-Adapter.md)
- [Extension API](./docs/Reference-Repository-Extension.md)
- [Share Configuration Reference](./docs/Reference-Repository.md)
diff --git a/docs/Reference-Adapter.md b/docs/Reference-Adapter.md
new file mode 100644
index 0000000..752bd99
--- /dev/null
+++ b/docs/Reference-Adapter.md
@@ -0,0 +1,97 @@
+# Keycloak Adapter Configuration Reference
+
+Both the Repository and Share sub-modules of this addon use the Keycloak-provided adapter library to easily integrate with the Keycloak authentication server. In order to retain much of the adapter libraries flexibility when it comes to different deployment scenarios / configurations that Keycloak is able to handle, most of the configuration properties of this library have been exposed for configuration in both the Repository-tier Keycloak authentication subsystem and the Share-tier `share-config-custom.xml`.
+
+Configuration of adapter properties in the Repository-tier subsystem is straight-forward. Properties can be either configured in `alfresco-global.properties` or within the subsystems extension path, e.g. in a `alfresco/extension/subsystems/Authentication/keycloak/keycloak1/*.properties` (assuming the `authentication.chain` contains a value for `keycloak1:keycloak`). All adapter-specific properties use the common key prefix of `keycloak.adapter.`, with the remaining key denoting the specific property to set. In case a particular property of the Keycloak adapter library denotes a map, entries can be specified by simply appending the entry key to property key, e.g. if `keycloak.adapter.propertyX` denotes a map, `keycloak.adapter.propertyX.key1=value1` would set `value1` in the map for the key `key1`.
+
+Configuration of adapter properties in the Share-tier `share-config-custom.xml` is also straight-forward. Instead of using a common property key prefix, the configuration properties are all child elements of the same XML structure. Multiple configuration sections can be defined and their configuration will be properly merged with a reliable last-wins behaviour. Map entries are handled by specifying entry keys as sub-elements of the map-based property. As part of the merging behaviour, any element which is redefined in a later configuration section with an empty value is effectively removed from the configuration - this is in contrast to Alfresco Share's default merging behaviour which generally does not support easy removal of configurations.
+
+`share-config-custom.xml` example for adapter configuration:
+
+```xml
+
+
+
+ http://localhost:8180/auth
+ alfresco
+ alfresco-share
+
+ secret
+ ...
+
+
+
+```
+
+## Supported Adapter Properties
+
+Note: This listing does not include the common property key prefix `keycloak.adapter.` that needs to be prepended in Repository-tier configuration.
+
+| Property | Default Value | Description |
+| --- | ---: | --- |
+| `auth-server-url` | `http://localhost:8180/auth` | Publically resolvable base URL to the Keycloak server to be used in redirect URLs and remote calls |
+| `directAuthHost` | | Alternative base URL for the Keycloak server (excluding path) to be used for calls from Alfresco to Keycloak - useful e.g. in scenarios where the regular `auth-server-url` can not be resolved or round-trips via a public gateway / proxy should be avoided |
+| `realm` | `alfresco` | Technical name of the Keycloak realm |
+| `realm-public-key` | | Fixed public key of the realm (PEM string) - if not set, the public key(s) will be dynamically loaded and automatically refreshed after a configurable amount of times between JSON Web Key Store requests |
+| `resource` | `alfresco` / `alfresco-share` | Technical name of the client set up in the realm |
+| `ssl-required` | `none` | SSL requirement mode, controlling both redirect URL generation and redirect validation - defaults to `none` for simple default deployment, but should typically be set to `external` (localhost / loopback requests may use HTTP) or `all` |
+| `confidential-port` | `-1` | SSL port to use when generating redirect URLs back to an SSL protected Alfresco resource - when a value of `-1` is configured, the addon will try to determine the port from the request, e.g. if a request contains a `X-Forwarded-Port` port with either port `80`/`443`, it is assumed Alfresco is operated behind a proxy and port `443` is used, otherwise the module will try to determine the SSL port from the raw request and fall back to the Tomcat default SSL port `8443`. This property **must to be changed** if Alfresco is operated in any constellation other than previously described. |
+| `bearer-only` | `false` | Flag determining whether authentication handling is terminated after checking for bearer token |
+| `autodetect-bearer-only` | `false` | Flag determining whether the Keycloak adapter library should attempt to determine if authentication handling for a request should be terminated after checking for bearer token (i.e. XMLHttpRequest, SOAPAction, or partial Faces requests, or any other request that does not accept `text/html`, `text/*` or `*/*` response content types) |
+| `enable-basic-auth` | `false` | Flag determining whether the Keycloak adapter library should handle basic authentications - if enabled, this supersedes any Alfresco provided basic authentication handling, limiting users to Keycloak-authenticated users only |
+| `public-client` | `false` | Flag whether the client uses the authentication flow of an OAuth public client |
+| `credentials` | | Map of credential parameters use to configure the way the client authenticates against Keycloak for direct requests |
+| `credentials.provider` | `secret` | Type of credential provider to use for client authentication - out-of-the-box, this addon supports `secret`, `jwt` and `secret-jwt` providers, while additional providers can be provided via Java's `ServiceLoader` facility, using the `ClientCredentialsProvider` interface in the shaded Repository / Share dependencies sub-module |
+| `credentials.secret` | | Value of the shared secret to use when either the `secret` or `secret-jwt` credential provider is used |
+| `credentials.algorithm` | `HS256` | Signing algorithm to use when the `secret-jwt` credential provider is used |
+| `credentials.client-keystore-file` | | File or class path location of the client's keystore, when the `jwt` credential provider is used |
+| `credentials.client-keystore-type` | | Type of the client's keystore, when the `jwt` credential provider is used |
+| `credentials.client-keystore-password` | | Password of the client's keystore, when the `jwt` credential provider is used |
+| `credentials.client-key-password` | | Password of the client's key inside the keystore, when the `jwt` credential provider is used |
+| `credentials.client-key-alias` | | Alias of the client's key inside the keystore, when the `jwt` credential provider is used |
+| `redirect-rewrite-rules` | | Map of key-value replacement tokens for dynamically rewriting the path of the generated redirect URI - note: only one / the first map entry will actually be processed by the Keycloak adapter library |
+| `allow-any-hostname` | `false` | Flag whether to disable the host name verification on the Apache HTTP client used to call Keycloak |
+| `disable-trust-manager` | `false` | Flag whether to disable the trust manager on the Apache HTTP client used to call Keycloak |
+| `truststore` | | File or class path location of the client's custom truststore for validating Keycloak's SSL server certificate |
+| `truststore-password` | | Password of the client's custom truststore for validating Keycloak's SSL server certificate |
+| `client-keystore` | | File or class path location of the client's keystore containing its SSL client certificate to be presented to the Keycloak server |
+| `client-keystore-password` | | Password for the client's keystore containing its SSL client certificate to be presented to the Keycloak server |
+| `client-key-password` | | Password for the client's key within the keystore containing its SSL client certificate to be presented to the Keycloak server |
+| `connection-pool-size` | `20` | Number of connections in the Apache HTTP clients connection pool for calls to the Keycloak server |
+| `always-refresh-token` | `true` | Flag determining whether a user's access token should always be refreshed when its remaining time-to-live is less than the allowed minimum value, or it has already expired - if `false`, user logins in Alfresco will effectively expire and require a new (transparent) authentication via Keycloak, as no component in the addon performs an explicit refresh |
+| `adapter-state-cookie-path` | | The path to use for the client cookie holding adapter state during execution of the authentication redirects - if not set, this will use the context path from the raw request, which is typically the correct value to use |
+| `principal-attribute` | | The name of the attribute to extract from the access token as an override to the token's subject for the name of the authenticated principal - since this addon does not use the principal name for anything (only the `preferred_username`), this configuration likely has no practical effect if changed |
+| `token-minimum-time-to-live` | | The minimum allowed time-to-live for an access token in seconds - if an access token is returned by Keycloak in exchange for an authorisation code or as part of a token refresh with a lower time-to-live, the validation of that token will fail |
+| `min-time-between-jwks-requests` | `10` | The minimum time in seconds that must be elapsed between two JSON Web Key Store requests to Keycloak to load public key(s) of the realm |
+| `public-key-cache-ttl` | `86400` | Time-to-live in seconds for public key cache entries |
+| `ignore-oauth-query-parameter` | `false` | Flag determining whether OAuth `access_token` in an URL query is to be ignored |
+| `verify-token-audience` | `true` / `false` | Flag enabling validation of the audience specified in an access token, enabled by default on the Repository-tier - must be disabled if Share or any other application which authenticates users via Keycloak is not delegating user authentication using RFC 8693 OAuth 2.0 Token Exchange |
+
+## Non-Standard Adapter Properties
+
+The following properties are not supported by the Keycloak adapter library, but have been added by the addon for customisation of the adapter's behaviour.
+
+| Property | Default Value | Description |
+| --- | ---: | --- |
+| `connectionTimeout` | `-1` | Connect timeout for the Apache HTTP client used in calls to Keycloak |
+| `socketTimeout` | `-1` | General socket timeout for the Apache HTTP client used in calls to Keycloak |
+
+## Unsupported Adapter Properties
+
+This listing details configuration properties from the Keycloak adapter library which are not supported by this addon and may result in `UnsupportedOperationException` or other errors potentially being triggered at runtime when set to a non-default value.
+
+| Property | Default Value | Description |
+| --- | ---: | --- |
+| `use-resource-role-mappings` | `false` | Flag effectively limited to determining whether resource config on Keycloak can override the realm's caller verification setting. If caller verification is required, clients must provide a certificate. - This is not supported by the Keycloak adapter library outside of a JBoss deployment. |
+| `enable-cors` | `false` | Flag enabling special handling for CORS requests (e.g. containing an Origin header). - No tests or special considerations have been done for CORS requests, as CORS should not be relevant in a proper Alfresco setup (e.g. whenever CORS would be needed for an ADF app or similar SPA, a simple proxy should do the trick without all the complexities of CORS). Additionally, CORS handling in Alfresco is already [provided out-of-the-box](https://docs.alfresco.com/6.2/concepts/enabling-cors.html). |
+| `cors-max-age` | `-1` | Value for the HTTP `Access-Control-Max-Age` response header |
+| `cors-allowed-headers` | | Value for the HTTP `Access-Control-Allow-Headers` response header |
+| `cors-allowed-methods` | | Value for the HTTP `Access-Control-Allow-Methods` response header |
+| `cors-exposed-headers` | | Value for the HTTP `Access-Control-Expose-Headers`response header |
+| `expose-token` | `false` | Flag determining whether CORS requests can retrieve a bearer token via special request URI |
+| `register-node-at-startup` | `false` | Flag determining whether the Keycloak adapter will register the node (server) with the Keycloak server - not relevant on Alfresco installations as this relates to [clustering on JBoss server technology](https://www.keycloak.org/docs/latest/securing_apps/#_applicationclustering), this addon already handles relevant caches for potential clustering in Alfresco Enterprise, and the necessary component of the Keycloak adapter library is not used in the integration of this addon |
+| `register-node-period` | `-1` | Time in seconds between node registration requests |
+| `token-store` | `session` | Mode for how the Keycloak adapter stores user account information - related to clustering like previous two settings and not relevant for the integration as provided by the addon |
+| `turn-off-change-session-id-on-login` | | Completely unused flag in the Keycloak adapter library |
+| `policy-enforcer` | | Complex configuration object determining fine-grained access policies to the Repository / Share application. - This is currently not supported for configuration by the addon due to use of complex object structures |
+| `enable-pkce` | `false` | RFC 7636 - Flag enabling the use of the Proof Key for Code Exchange for OAuth public clients. - This has not yet implemented by the Keycloak adapter library. |
\ No newline at end of file
diff --git a/docs/Simple-Configuration.md b/docs/Simple-Configuration.md
index 4b519bd..f0498de 100644
--- a/docs/Simple-Configuration.md
+++ b/docs/Simple-Configuration.md
@@ -99,11 +99,11 @@ The following core configuration properties can be set (more extensive list in t
| `...groupFilter.containedInGroup.property.groupPaths` | | Comma-separated list of group paths (e.g. `/Group A/Group B,/Group A/Group C`) to use in filtering which groups are synchronised to Alfresco (by default - configured separately - any match qualifies, and transitive containment is considered) |
| `...groupFilter.containedInGroup.property.groupIds` | | Comma-separated list of group IDs to use in filtering which groups are synchronised to Alfresco (by default - configured separately - any match qualifies, and transitive containment is considered) |
| `keycloak.adapter.auth-server-url` | `http://localhost:8180/auth` | Publically resolvable base URL to the Keycloak server to be used in redirect URLs and remote calls |
-| `keycloak.authentication.directAuthHost` | | Alternative base URL for the Keycloak server (excluding path) to be used for calls from Alfresco to Keycloak - useful e.g. in scenarios where the regular `auth-server-url` can not be resolved by the Alfresco Repository host or round-trips via a public gateway / proxy should be avoided |
-| `keycloak.adapter.realm` | `alfresco` | Technical name of the Keycloak realm |
-| `keycloak.adapter.resource` | `alfresco` | Technical name of the client set up for the Alfresco Repository in the realm |
-| `keycloak.adapter.keycloak.adapter.credentials.secret` | | Shared secret for validation of authorisation codes / access tokens |
-| `keycloak.adapter.verify-token-audience` | `true` | Flag enabling validation of the audience specified in an access token - must be disabled if Share or any other application which authenticates users via Keycloak is not delegating user authentication using RFC 8693 OAuth 2.0 Token Exchange |
+| `...directAuthHost` | | Alternative base URL for the Keycloak server (excluding path) to be used for calls from Alfresco to Keycloak - useful e.g. in scenarios where the regular `auth-server-url` can not be resolved by the Alfresco Repository host or round-trips via a public gateway / proxy should be avoided |
+| `...realm` | `alfresco` | Technical name of the Keycloak realm |
+| `...resource` | `alfresco` | Technical name of the client set up for the Alfresco Repository in the realm |
+| `...keycloak.adapter.credentials.secret` | | Shared secret for validation of authorisation codes / access tokens |
+| `...verify-token-audience` | `true` | Flag enabling validation of the audience specified in an access token - must be disabled if Share or any other application which authenticates users via Keycloak is not delegating user authentication using RFC 8693 OAuth 2.0 Token Exchange |
## Alfresco Share
diff --git a/repository/src/main/globalConfig/subsystems/Authentication/keycloak/keycloak-authentication-context.xml b/repository/src/main/globalConfig/subsystems/Authentication/keycloak/keycloak-authentication-context.xml
index 70085ba..ed1f3ac 100644
--- a/repository/src/main/globalConfig/subsystems/Authentication/keycloak/keycloak-authentication-context.xml
+++ b/repository/src/main/globalConfig/subsystems/Authentication/keycloak/keycloak-authentication-context.xml
@@ -30,9 +30,9 @@
-
-
-
+
+
+
@@ -135,7 +135,6 @@
-
diff --git a/repository/src/main/globalConfig/subsystems/Authentication/keycloak/keycloak-authentication.properties b/repository/src/main/globalConfig/subsystems/Authentication/keycloak/keycloak-authentication.properties
index 96f0965..15601ce 100644
--- a/repository/src/main/globalConfig/subsystems/Authentication/keycloak/keycloak-authentication.properties
+++ b/repository/src/main/globalConfig/subsystems/Authentication/keycloak/keycloak-authentication.properties
@@ -13,19 +13,20 @@ keycloak.authentication.mapPersonPropertiesOnLogin=true
keycloak.authentication.authenticateFTP=true
keycloak.authentication.silentRemoteUserValidationFailure=true
-keycloak.authentication.connectionTimeout=-1
-keycloak.authentication.socketTimeout=-1
-keycloak.authentication.sslRedirectPort=8443
keycloak.authentication.bodyBufferLimit=10485760
# override for a direct route to the auth server host
# 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.directAuthHost=
+# other custom adapter properties not part of default Keycloak adapter library
+keycloak.adapter.connectionTimeout=-1
+keycloak.adapter.socketTimeout=-1
keycloak.adapter.auth-server-url=http://localhost:8180/auth
keycloak.adapter.realm=alfresco
keycloak.adapter.resource=alfresco
keycloak.adapter.ssl-required=none
+keycloak.adapter.confidential-port=-1
keycloak.adapter.public-client=false
keycloak.adapter.credentials.provider=secret
keycloak.adapter.credentials.secret=
diff --git a/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakAuthenticationFilter.java b/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakAuthenticationFilter.java
index 5adf4bb..b64da14 100644
--- a/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakAuthenticationFilter.java
+++ b/repository/src/main/java/de/acosix/alfresco/keycloak/repo/authentication/KeycloakAuthenticationFilter.java
@@ -126,10 +126,6 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter
protected int bodyBufferLimit = DEFAULT_BODY_BUFFER_LIMIT;
- // use 8443 as default SSL redirect based on Tomcat default server.xml configuration
- // can't rely on SysAdminParams#getAlfrescoPort either because that may be proxied / non-SSL
- protected int sslRedirectPort = 8443;
-
protected KeycloakDeployment keycloakDeployment;
protected SessionIdMapper sessionIdMapper;
@@ -250,15 +246,6 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter
this.bodyBufferLimit = bodyBufferLimit;
}
- /**
- * @param sslRedirectPort
- * the sslRedirectPort to set
- */
- public void setSslRedirectPort(final int sslRedirectPort)
- {
- this.sslRedirectPort = sslRedirectPort;
- }
-
/**
* @param keycloakDeployment
* the keycloakDeployment to set
@@ -540,8 +527,11 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter
final OIDCFilterSessionStore tokenStore = new OIDCFilterSessionStore(req, facade,
this.bodyBufferLimit > 0 ? this.bodyBufferLimit : DEFAULT_BODY_BUFFER_LIMIT, this.keycloakDeployment, this.sessionIdMapper);
+
+ final int sslPort = this.determineLikelySslPort(req);
+
final FilterRequestAuthenticator authenticator = new FilterRequestAuthenticator(this.keycloakDeployment, tokenStore, facade, req,
- this.sslRedirectPort);
+ sslPort);
final AuthOutcome authOutcome = authenticator.authenticate();
if (authOutcome == AuthOutcome.AUTHENTICATED)
@@ -1252,6 +1242,38 @@ public class KeycloakAuthenticationFilter extends BaseAuthenticationFilter
}
}
+ /**
+ * Determines the likely SSL port to be used in redirects from the incoming request. This operation should only be used to determine a
+ * technical default value in lieu of an explicitly configured value.
+ *
+ * @param req
+ * the incoming request
+ * @return the assumed SSL port to be used in redirects
+ */
+ protected int determineLikelySslPort(final HttpServletRequest req)
+ {
+ int rqPort = req.getServerPort();
+ final String forwardedPort = req.getHeader("X-Forwarded-Port");
+ if (forwardedPort != null && forwardedPort.matches("^\\d+$"))
+ {
+ rqPort = Integer.parseInt(forwardedPort);
+ }
+ final int sslPort;
+ if (rqPort == 80 || rqPort == 443)
+ {
+ sslPort = 443;
+ }
+ else if (req.isSecure() && "https".equals(req.getScheme()))
+ {
+ sslPort = rqPort;
+ }
+ else
+ {
+ sslPort = 8443;
+ }
+ return sslPort;
+ }
+
/**
* {@inheritDoc}
*/
diff --git a/repository/src/test/docker/alfresco/extension/alfresco-global.addition.properties b/repository/src/test/docker/alfresco/extension/alfresco-global.addition.properties
index 55e8405..ea636db 100644
--- a/repository/src/test/docker/alfresco/extension/alfresco-global.addition.properties
+++ b/repository/src/test/docker/alfresco/extension/alfresco-global.addition.properties
@@ -25,7 +25,7 @@ keycloak.adapter.credentials.provider=secret
keycloak.adapter.credentials.secret=6f70a28f-98cd-41ca-8f2f-368a8797d708
# localhost in auth-server-url won't work for direct access in a Docker deployment
-keycloak.authentication.directAuthHost=http://keycloak:8080
+keycloak.adapter.directAuthHost=http://keycloak:8080
keycloak.synchronization.userFilter.containedInGroup.property.groupPaths=/Test A
keycloak.synchronization.groupFilter.containedInGroup.property.groupPaths=/Test A
diff --git a/share/src/main/config/default-config.xml b/share/src/main/config/default-config.xml
index 20a06eb..0bfed4d 100644
--- a/share/src/main/config/default-config.xml
+++ b/share/src/main/config/default-config.xml
@@ -31,8 +31,6 @@
true
true
false
-
- 8443
10485760
1000
true
@@ -43,8 +41,9 @@
http://localhost:8180/auth
alfresco
- alfresco
+ alfresco-share
none
+ -1
false
diff --git a/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAuthenticationConfigElement.java b/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAuthenticationConfigElement.java
index 7a0f85e..d47cd7e 100644
--- a/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAuthenticationConfigElement.java
+++ b/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAuthenticationConfigElement.java
@@ -39,8 +39,6 @@ public class KeycloakAuthenticationConfigElement extends BaseCustomConfigElement
protected final ConfigValueHolder bodyBufferLimit = new ConfigValueHolder<>();
- protected final ConfigValueHolder sslRedirectPort = new ConfigValueHolder<>();
-
protected final ConfigValueHolder sessionMapperLimit = new ConfigValueHolder<>();
protected final ConfigValueHolder ignoreDefaultFilter = new ConfigValueHolder<>();
@@ -125,23 +123,6 @@ public class KeycloakAuthenticationConfigElement extends BaseCustomConfigElement
return this.bodyBufferLimit.getValue();
}
- /**
- * @param sslRedirectPort
- * the sslRedirectPort to set
- */
- public void setSslRedirectPort(final Integer sslRedirectPort)
- {
- this.sslRedirectPort.setValue(sslRedirectPort);
- }
-
- /**
- * @return the sslRedirectPort
- */
- public Integer getSslRedirectPort()
- {
- return this.sslRedirectPort.getValue();
- }
-
/**
* @param sessionMapperLimit
* the sessionMapperLimit to set
@@ -265,16 +246,6 @@ public class KeycloakAuthenticationConfigElement extends BaseCustomConfigElement
otherConfigElement.getBodyBufferLimit() != null ? otherConfigElement.getBodyBufferLimit() : this.getBodyBufferLimit());
}
- if (otherConfigElement.sslRedirectPort.isUnset())
- {
- combined.sslRedirectPort.unset();
- }
- else
- {
- combined.setSslRedirectPort(
- otherConfigElement.getSslRedirectPort() != null ? otherConfigElement.getSslRedirectPort() : this.getSslRedirectPort());
- }
-
if (otherConfigElement.sessionMapperLimit.isUnset())
{
combined.sessionMapperLimit.unset();
@@ -341,9 +312,6 @@ public class KeycloakAuthenticationConfigElement extends BaseCustomConfigElement
builder.append("bodyBufferLimit=");
builder.append(this.bodyBufferLimit);
builder.append(", ");
- builder.append("sslRedirectPort=");
- builder.append(this.sslRedirectPort);
- builder.append(", ");
builder.append("sessionMapperLimit=");
builder.append(this.sessionMapperLimit);
builder.append(", ");
diff --git a/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAuthenticationConfigElementReader.java b/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAuthenticationConfigElementReader.java
index aceda88..fdd968e 100644
--- a/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAuthenticationConfigElementReader.java
+++ b/share/src/main/java/de/acosix/alfresco/keycloak/share/config/KeycloakAuthenticationConfigElementReader.java
@@ -65,13 +65,6 @@ public class KeycloakAuthenticationConfigElementReader implements ConfigElementR
configElement.setBodyBufferLimit(value.isEmpty() ? null : Integer.valueOf(value));
}
- final Element sslRedirectPort = element.element("ssl-redirect-port");
- if (sslRedirectPort != null)
- {
- final String value = sslRedirectPort.getTextTrim();
- configElement.setSslRedirectPort(value.isEmpty() ? null : Integer.valueOf(value));
- }
-
final Element sessionMapperLimit = element.element("session-mapper-limit");
if (sessionMapperLimit != null)
{
diff --git a/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java b/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java
index 3d8d1cb..77b3e02 100644
--- a/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java
+++ b/share/src/main/java/de/acosix/alfresco/keycloak/share/web/KeycloakAuthenticationFilter.java
@@ -556,7 +556,6 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
.getConfig(KeycloakConfigConstants.KEYCLOAK_CONFIG_SECTION_NAME).getConfigElement(KeycloakAuthenticationConfigElement.NAME);
final Integer bodyBufferLimit = keycloakAuthConfig.getBodyBufferLimit();
- final Integer sslRedirectPort = keycloakAuthConfig.getSslRedirectPort();
final OIDCServletHttpFacade facade = new OIDCServletHttpFacade(req, res);
@@ -604,7 +603,7 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
}
else
{
- this.processFilterAuthentication(context, req, res, chain, bodyBufferLimit, sslRedirectPort, facade);
+ this.processFilterAuthentication(context, req, res, chain, bodyBufferLimit, facade);
}
}
@@ -689,8 +688,6 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
* @param bodyBufferLimit
* the configured size limit to apply to any HTTP POST/PUT body buffering that may need to be applied to process the
* authentication via an intermediary redirect
- * @param sslRedirectPort
- * the configured port to use for any forced redirection to HTTPS/SSL communication
* @param facade
* the Keycloak HTTP facade
* @throws IOException
@@ -699,8 +696,7 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
* if any error occurs during Keycloak authentication or processing of the filter chain
*/
protected void processFilterAuthentication(final ServletContext context, final HttpServletRequest req, final HttpServletResponse res,
- final FilterChain chain, final Integer bodyBufferLimit, final Integer sslRedirectPort, final OIDCServletHttpFacade facade)
- throws IOException, ServletException
+ final FilterChain chain, final Integer bodyBufferLimit, final OIDCServletHttpFacade facade) throws IOException, ServletException
{
final OIDCFilterSessionStore tokenStore = new OIDCFilterSessionStore(req, facade,
bodyBufferLimit != null ? bodyBufferLimit.intValue() : DEFAULT_BODY_BUFFER_LIMIT, this.keycloakDeployment,
@@ -708,7 +704,7 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
// use 8443 as default SSL redirect based on Tomcat default server.xml configuration
final FilterRequestAuthenticator authenticator = new FilterRequestAuthenticator(this.keycloakDeployment, tokenStore, facade, req,
- sslRedirectPort != null ? sslRedirectPort.intValue() : 8443);
+ this.keycloakDeployment.getConfidentialPort());
final AuthOutcome authOutcome = authenticator.authenticate();
if (authOutcome == AuthOutcome.AUTHENTICATED)
@@ -814,7 +810,6 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
.getConfig(KeycloakConfigConstants.KEYCLOAK_CONFIG_SECTION_NAME).getConfigElement(KeycloakAuthenticationConfigElement.NAME);
final Integer bodyBufferLimit = keycloakAuthConfig.getBodyBufferLimit();
- final Integer sslRedirectPort = keycloakAuthConfig.getSslRedirectPort();
// fake a request that will yield a redirect
final HttpServletRequest wrappedReq = new HttpServletRequestWrapper(req)
@@ -838,9 +833,9 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
final OIDCFilterSessionStore tokenStore = new OIDCFilterSessionStore(req, captureFacade,
bodyBufferLimit != null ? bodyBufferLimit.intValue() : DEFAULT_BODY_BUFFER_LIMIT, this.keycloakDeployment, null);
- // use 8443 as default SSL redirect based on Tomcat default server.xml configuration
- final OAuthRequestAuthenticator authenticator = new OAuthRequestAuthenticator(null, captureFacade, this.keycloakDeployment,
- sslRedirectPort != null ? sslRedirectPort.intValue() : 8443, tokenStore);
+ final int sslPort = this.determineLikelySslPort(req);
+ final OAuthRequestAuthenticator authenticator = new OAuthRequestAuthenticator(null, captureFacade, this.keycloakDeployment, sslPort,
+ tokenStore);
final AuthOutcome authOutcome = authenticator.authenticate();
if (authOutcome != AuthOutcome.NOT_ATTEMPTED)
@@ -1781,6 +1776,38 @@ public class KeycloakAuthenticationFilter implements DependencyInjectedFilter, I
}
}
+ /**
+ * Determines the likely SSL port to be used in redirects from the incoming request. This operation should only be used to determine a
+ * technical default value in lieu of an explicitly configured value.
+ *
+ * @param req
+ * the incoming request
+ * @return the assumed SSL port to be used in redirects
+ */
+ protected int determineLikelySslPort(final HttpServletRequest req)
+ {
+ int rqPort = req.getServerPort();
+ final String forwardedPort = req.getHeader("X-Forwarded-Port");
+ if (forwardedPort != null && forwardedPort.matches("^\\d+$"))
+ {
+ rqPort = Integer.parseInt(forwardedPort);
+ }
+ final int sslPort;
+ if (rqPort == 80 || rqPort == 443)
+ {
+ sslPort = 443;
+ }
+ else if (req.isSecure() && "https".equals(req.getScheme()))
+ {
+ sslPort = rqPort;
+ }
+ else
+ {
+ sslPort = 8443;
+ }
+ return sslPort;
+ }
+
/**
* Sets up a forced route for the Keycloak-library backing HTTP client if configured. This may be necessary to deal with situations
* where Share cannot use the public address of the authentication server (used in authentication redirects) to talk with the server
diff --git a/share/src/test/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigTest.java b/share/src/test/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigTest.java
index b934283..266ece2 100644
--- a/share/src/test/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigTest.java
+++ b/share/src/test/java/de/acosix/alfresco/keycloak/share/config/KeycloakAdapterConfigTest.java
@@ -52,7 +52,6 @@ public class KeycloakAdapterConfigTest
Assert.assertTrue(keycloakAuthConfig.getEnhanceLoginForm());
Assert.assertTrue(keycloakAuthConfig.getEnableSsoFilter());
Assert.assertFalse(keycloakAuthConfig.getForceKeycloakSso());
- Assert.assertEquals(Integer.valueOf(8443), keycloakAuthConfig.getSslRedirectPort());
Assert.assertEquals(Integer.valueOf(10485760), keycloakAuthConfig.getBodyBufferLimit());
Assert.assertEquals(Integer.valueOf(1000), keycloakAuthConfig.getSessionMapperLimit());
@@ -99,7 +98,6 @@ public class KeycloakAdapterConfigTest
Assert.assertFalse(keycloakAuthConfig.getEnhanceLoginForm());
Assert.assertFalse(keycloakAuthConfig.getEnableSsoFilter());
Assert.assertFalse(keycloakAuthConfig.getForceKeycloakSso());
- Assert.assertEquals(Integer.valueOf(8443), keycloakAuthConfig.getSslRedirectPort());
Assert.assertEquals(Integer.valueOf(10485760), keycloakAuthConfig.getBodyBufferLimit());
Assert.assertEquals(Integer.valueOf(2000), keycloakAuthConfig.getSessionMapperLimit());
diff --git a/share/src/test/resources/default-config.xml b/share/src/test/resources/default-config.xml
index eabf189..8d12e5c 100644
--- a/share/src/test/resources/default-config.xml
+++ b/share/src/test/resources/default-config.xml
@@ -40,6 +40,7 @@
alfresco
+ http://keycloak:8080
http://localhost:8180/auth
alfresco