diff --git a/README.md b/README.md
index ede48b35..b0715c6f 100644
--- a/README.md
+++ b/README.md
@@ -20,7 +20,7 @@ This plugin provides the basis for using Keycloak as Identity Management solutio
Password grant exchanges are only supported for Keycloak's internally managed users and users of an LDAP / Keberos User federation. Hence without SSO you will only be able to login with users managed by such connections.
Current version: `7.20.0-SNAPSHOT`
-Latest tests with: Keycloak `21.1.1`, `19.0.3-legacy`, Camunda `7.20.0-alpha4`
+Latest tests with: Keycloak `21.1.1`, `19.0.3-legacy`, Camunda `7.20.0-alpha5`
#### Features
Changes in version `7.20.0`
@@ -135,7 +135,7 @@ Maven Dependencies:
org.camunda.bpm.extension
camunda-platform-7-keycloak
- 7.18.0
+ 7.20.0
```
@@ -298,28 +298,30 @@ Last but not least add a security configuration and enable OAuth2 SSO:
```java
/**
-* Camunda Web application SSO configuration for usage with KeycloakIdentityProviderPlugin.
-*/
+ * Camunda Web application SSO configuration for usage with KeycloakIdentityProviderPlugin.
+ */
@ConditionalOnMissingClass("org.springframework.test.context.junit.jupiter.SpringExtension")
+@EnableWebSecurity
@Configuration
-@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
-public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {
+public class WebAppSecurityConfig {
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http
- .csrf().ignoringAntMatchers("/api/**")
- .and()
- .requestMatchers().antMatchers("/**").and()
- .authorizeRequests(authorizeRequests ->
- authorizeRequests
- .antMatchers("/app/**", "/api/**", "/lib/**")
- .authenticated()
- .anyRequest()
- .permitAll()
- )
- .oauth2Login()
- ;
+ @Bean
+ @Order(1)
+ public SecurityFilterChain httpSecurity(HttpSecurity http) throws Exception {
+ return http
+ .csrf(csrf -> csrf
+ .ignoringRequestMatchers(antMatcher("/api/**"), antMatcher("/engine-rest/**")))
+ .authorizeHttpRequests(authorize -> authorize
+ .requestMatchers(
+ antMatcher("/assets/**"),
+ antMatcher("/app/**"),
+ antMatcher("/api/**"),
+ antMatcher("/lib/**"))
+ .authenticated()
+ .anyRequest()
+ .permitAll())
+ .oauth2Login(withDefaults())
+ .build();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@@ -334,6 +336,16 @@ public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {
return filterRegistration;
}
+ // The ForwardedHeaderFilter is required to correctly assemble the redirect URL for OAUth2 login.
+ // Without the filter, Spring generates an HTTP URL even though the container route is accessed through HTTPS.
+ @Bean
+ public FilterRegistrationBean forwardedHeaderFilter() {
+ FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean<>();
+ filterRegistrationBean.setFilter(new ForwardedHeaderFilter());
+ filterRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
+ return filterRegistrationBean;
+ }
+
@Bean
@Order(0)
public RequestContextListener requestContextListener() {
@@ -465,4 +477,3 @@ Brought to you by:
## License
License: [Apache License 2.0](https://opensource.org/licenses/Apache-2.0)
-
diff --git a/examples/jwt/README.md b/examples/jwt/README.md
index 9d0f924d..6d64ad96 100644
--- a/examples/jwt/README.md
+++ b/examples/jwt/README.md
@@ -67,9 +67,10 @@ In order to setup Spring Boot's OAuth2 security add the following Maven dependen
With all that stuff in place we then need a Web Security Configuration as follows:
```java
+@ConditionalOnMissingClass("org.springframework.test.context.junit.jupiter.SpringExtension")
@Configuration
-@Order(SecurityProperties.BASIC_AUTH_ORDER - 10)
-public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {
+@EnableWebSecurity
+public class WebAppSecurityConfig {
private static final int AFTER_SPRING_SECURITY_FILTER_CHAIN_ORDER = 201;
private static final String API_FILTER_PATTERN = "/api/*";
@@ -81,22 +82,24 @@ public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {
@Inject
private KeycloakCockpitConfiguration keycloakCockpitConfiguration;
- @Override
- protected void configure(HttpSecurity http) throws Exception {
+ @Bean
+ public SecurityFilterChain httpSecurity(HttpSecurity http) throws Exception {
String path = camundaBpmProperties.getWebapp().getApplicationPath();
- http
- .csrf().ignoringAntMatchers("/api/**", "/engine-rest/**")
- .and()
- .requestMatchers().antMatchers("/**").and()
- .authorizeRequests(authz -> authz
- .antMatchers( "/").permitAll()
- .antMatchers(path + "/app/**").permitAll()
- .antMatchers(path + "/lib/**").permitAll()
- .antMatchers(path + "/api/engine/engine/**").permitAll()
- .antMatchers(path + "/api/*/plugin/*/static/app/plugin.css").permitAll()
- .antMatchers(path + "/api/*/plugin/*/static/app/plugin.js").permitAll()
+ return http
+ .csrf(csrf -> csrf
+ .ignoringRequestMatchers(antMatcher(path + "/api/**"), antMatcher("/engine-rest/**")))
+ .securityMatcher("/**")
+ .authorizeHttpRequests(authz -> authz
+ .requestMatchers(antMatcher("/")).permitAll()
+ .requestMatchers(antMatcher(path + "/app/**")).permitAll()
+ .requestMatchers(antMatcher(path + "/assets/**")).permitAll()
+ .requestMatchers(antMatcher(path + "/lib/**")).permitAll()
+ .requestMatchers(antMatcher(path + "/api/engine/engine/**")).permitAll()
+ .requestMatchers(antMatcher(path + "/api/*/plugin/*/static/app/plugin.css")).permitAll()
+ .requestMatchers(antMatcher(path + "/api/*/plugin/*/static/app/plugin.js")).permitAll()
.anyRequest().authenticated())
- .oauth2ResourceServer(oauth2 -> oauth2.jwt());
+ .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()))
+ .build();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@@ -105,7 +108,7 @@ public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {
String camundaWebappPath = camundaBpmProperties.getWebapp().getApplicationPath();
FilterRegistrationBean filterRegistration = new FilterRegistrationBean();
- filterRegistration.setFilter(new KeycloakJwtAuthenticationFilter());
+ filterRegistration.setFilter(new KeycloakJwtAuthenticationFilter(camundaWebappPath));
filterRegistration.setInitParameters(Collections.singletonMap("authentication-provider", "org.camunda.bpm.extension.keycloak.auth.KeycloakJwtAuthenticationProvider"));
filterRegistration.setName(AUTHENTICATION_FILTER_NAME);
filterRegistration.setOrder(AFTER_SPRING_SECURITY_FILTER_CHAIN_ORDER);
@@ -156,16 +159,15 @@ Also for camunda 7.18+ you need to configure CSP header:
camunda.bpm:
webapp:
header-security:
- content-security-policy-value=: "base-uri 'self';
- script-src $NONCE 'strict-dynamic' 'unsafe-eval' https: 'self' 'unsafe-inline';
- style-src 'unsafe-inline' 'self';
- connect-src ${plugin.cockpit.keycloak.keycloakUrl} 'self';
- default-src 'self';
- img-src 'self' data:;
- block-all-mixed-content;form-action 'self';
- frame-ancestors 'none';object-src 'none';
- sandbox allow-forms allow-scripts allow-same-origin allow-popups allow-downloads"
-
+ content-security-policy-value: "base-uri 'self';
+ script-src $NONCE 'strict-dynamic' 'unsafe-eval' https: 'self' 'unsafe-inline';
+ style-src 'unsafe-inline' 'self';
+ connect-src ${keycloak.url} 'self';
+ default-src 'self';
+ img-src 'self' data:;
+ block-all-mixed-content;form-action 'self';
+ frame-ancestors 'none';object-src 'none';
+ sandbox allow-forms allow-scripts allow-same-origin allow-popups allow-downloads"
```
Now you are ready for the last step: activate Keycloak on the client side.
@@ -184,5 +186,5 @@ export default {
};
```
-The referenced script takes care of loading `/js/keycloak.min.js` from your Keycloak server and integrates the Authorization into the Cockpit app
+The referenced script takes care of loading the [Keycloak Javascript adapter](https://www.keycloak.org/docs/latest/securing_apps/#_javascript_adapter) and integrates the Authorization into the Cockpit app
using parameters as configured in the Spring Boot config file.
\ No newline at end of file
diff --git a/examples/run/README.md b/examples/run/README.md
index c694c5d5..e5928b96 100644
--- a/examples/run/README.md
+++ b/examples/run/README.md
@@ -9,15 +9,13 @@ Please be aware that you must use the provided ``*-run-x.y.z.jar`` (fat jar, pac
For the records - included dependencies are:
-* org.apache.httpcomponents:httpclient
- * org.apache.httpcomponents:httpcore
- * commons-codec:commons-codec
+* org.apache.httpcomponents:client5
+ * org.apache.httpcomponents:core5
* com.google.code.gson:gson
* com.github.ben-manes.caffeine:caffeine
* org.checkerframework:checker-qual
* com.google.errorprone:error_prone_annotations
-
The ``com.google.code.gson`` and ``com.github.ben-manes.caffeine`` dependencies are shaded into the ``keycloakjar`` package namespace. Please be aware ``httpclient`` dependencies (including transitive ones) are not(!) shaded.
## Configure the Keycloak Identity Provider Plugin
diff --git a/examples/sso-kubernetes/src/main/java/org/camunda/bpm/extension/keycloak/showcase/sso/WebAppSecurityConfig.java b/examples/sso-kubernetes/src/main/java/org/camunda/bpm/extension/keycloak/showcase/sso/WebAppSecurityConfig.java
index 33dbf1c3..ef261386 100644
--- a/examples/sso-kubernetes/src/main/java/org/camunda/bpm/extension/keycloak/showcase/sso/WebAppSecurityConfig.java
+++ b/examples/sso-kubernetes/src/main/java/org/camunda/bpm/extension/keycloak/showcase/sso/WebAppSecurityConfig.java
@@ -30,9 +30,9 @@ public class WebAppSecurityConfig {
@Inject
private KeycloakLogoutHandler keycloakLogoutHandler;
- @Bean
- @Order(1)
- public SecurityFilterChain httpSecurity(HttpSecurity http) throws Exception {
+ @Bean
+ @Order(1)
+ public SecurityFilterChain httpSecurity(HttpSecurity http) throws Exception {
return http
.csrf(csrf -> csrf
.ignoringRequestMatchers(antMatcher("/api/**"), antMatcher("/engine-rest/**")))
@@ -51,7 +51,7 @@ public SecurityFilterChain httpSecurity(HttpSecurity http) throws Exception {
.logoutSuccessHandler(keycloakLogoutHandler)
)
.build();
- }
+ }
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean
diff --git a/examples/tomcat/README.md b/examples/tomcat/README.md
index c18d89b0..eda39620 100644
--- a/examples/tomcat/README.md
+++ b/examples/tomcat/README.md
@@ -17,9 +17,8 @@ For the records - included dependencies are:
* org.springframework:spring-beans
* org.springframework:spring-core
* org.springframework:spring-jcl
-* org.apache.httpcomponents:httpclient
- * org.apache.httpcomponents:httpcore
- * commons-codec:commons-codec
+* org.apache.httpcomponents:client5
+ * org.apache.httpcomponents:core5
* com.github.ben-manes.caffeine:caffeine
* org.checkerframework:checker-qual
* com.google.errorprone:error_prone_annotations