From aaf9acec84a052515b8e2bd33abfb811e3ca6674 Mon Sep 17 00:00:00 2001 From: Daniel Kelemen Date: Fri, 13 Sep 2024 15:49:56 +0200 Subject: [PATCH 1/5] feat(oauth2): add sso logout support https://github.com/camunda/camunda-bpm-platform/issues/4455 --- ...SpringSecurityOAuth2AutoConfiguration.java | 26 ++++++++-- .../security/oauth2/OAuth2Properties.java | 48 ++++++++++++++++++- 2 files changed, 69 insertions(+), 5 deletions(-) diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java index 7668affdb05..a9b69bed133 100644 --- a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java @@ -45,9 +45,12 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; +import org.springframework.security.oauth2.client.oidc.web.logout.OidcClientInitiatedLogoutSuccessHandler; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter; import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import java.util.Map; @@ -98,9 +101,17 @@ protected GrantedAuthoritiesMapper grantedAuthoritiesMapper() { return new OAuth2GrantedAuthoritiesMapper(oAuth2Properties); } + protected LogoutSuccessHandler oidcLogoutSuccessHandler(ClientRegistrationRepository clientRegistrationRepository) { + var oidcLogoutSuccessHandler = new OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository); + // Redirected after the logout has been performed at the provider + oidcLogoutSuccessHandler.setPostLogoutRedirectUri(oAuth2Properties.getSsoLogout().getPostLogoutRedirectUri()); + return oidcLogoutSuccessHandler; + } + @Bean - public SecurityFilterChain filterChain(HttpSecurity http, OAuth2AuthorizedClientManager clientManager) - throws Exception { + public SecurityFilterChain filterChain(HttpSecurity http, + ClientRegistrationRepository clientRegistrationRepository, + OAuth2AuthorizedClientManager clientManager) throws Exception { logger.info("Enabling Camunda Spring Security oauth2 integration"); var validateTokenFilter = new AuthorizeTokenFilter(clientManager); @@ -113,13 +124,22 @@ public SecurityFilterChain filterChain(HttpSecurity http, OAuth2AuthorizedClient ) .addFilterAfter(validateTokenFilter, OAuth2AuthorizationRequestRedirectFilter.class) .anonymous(AbstractHttpConfigurer::disable) + .oidcLogout(c -> c.backChannel(Customizer.withDefaults())) .oauth2Login(Customizer.withDefaults()) - .oidcLogout(Customizer.withDefaults()) + .logout(c -> c + //.logoutUrl("") + .clearAuthentication(true) + .invalidateHttpSession(true) + ) .oauth2Client(Customizer.withDefaults()) .cors(AbstractHttpConfigurer::disable) .csrf(AbstractHttpConfigurer::disable); // @formatter:on + if (oAuth2Properties.getSsoLogout().isEnabled()) { + http.logout(c -> c.logoutSuccessHandler(oidcLogoutSuccessHandler(clientRegistrationRepository))); + } + return http.build(); } diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/OAuth2Properties.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/OAuth2Properties.java index d9396842ae9..4b341a58f5b 100644 --- a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/OAuth2Properties.java +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/OAuth2Properties.java @@ -16,19 +16,55 @@ */ package org.camunda.bpm.spring.boot.starter.security.oauth2; -import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.OAuth2IdentityProvider; import org.camunda.bpm.spring.boot.starter.property.CamundaBpmProperties; +import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.OAuth2IdentityProvider; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; @ConfigurationProperties(OAuth2Properties.PREFIX) public class OAuth2Properties { public static final String PREFIX = CamundaBpmProperties.PREFIX + ".oauth2"; + /** + * OAuth2 SSO logout properties. + */ + @NestedConfigurationProperty + private OAuth2SSOLogoutProperties ssoLogout = new OAuth2SSOLogoutProperties(); + /** * OAuth2 identity provider properties. */ - private OAuth2IdentityProviderProperties identityProvider; + @NestedConfigurationProperty + private OAuth2IdentityProviderProperties identityProvider = new OAuth2IdentityProviderProperties(); + + public static class OAuth2SSOLogoutProperties { + /** + * Enable SSO Logout. Default {@code false}. + */ + private boolean enabled = false; + + /** + * Enable SSO Logout. Default {@code {baseUrl}}. + */ + private String postLogoutRedirectUri = "{baseUrl}"; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getPostLogoutRedirectUri() { + return postLogoutRedirectUri; + } + + public void setPostLogoutRedirectUri(String postLogoutRedirectUri) { + this.postLogoutRedirectUri = postLogoutRedirectUri; + } + } public static class OAuth2IdentityProviderProperties { /** @@ -71,6 +107,14 @@ public void setGroupNameDelimiter(String groupNameDelimiter) { } } + public OAuth2SSOLogoutProperties getSsoLogout() { + return ssoLogout; + } + + public void setSsoLogout(OAuth2SSOLogoutProperties ssoLogout) { + this.ssoLogout = ssoLogout; + } + public OAuth2IdentityProviderProperties getIdentityProvider() { return identityProvider; } From 86dfda89667ebc2f1ced27dad1373ec5e7fac925 Mon Sep 17 00:00:00 2001 From: Daniel Kelemen Date: Wed, 18 Sep 2024 13:03:59 +0200 Subject: [PATCH 2/5] add logout plugin --- ...SpringSecurityOAuth2AutoConfiguration.java | 1 - .../impl/plugin/SsoLogoutPluginConstants.java | 23 ++++++++++ .../plugin/admin/SsoLogoutAdminPlugin.java | 36 ++++++++++++++++ .../SsoLogoutAdminPluginRootResource.java | 30 +++++++++++++ .../cockpit/SsoLogoutCockpitPlugin.java | 36 ++++++++++++++++ .../SsoLogoutCockpitPluginRootResource.java | 30 +++++++++++++ .../tasklist/SsoLogoutTasklistPlugin.java | 36 ++++++++++++++++ .../SsoLogoutTasklistPluginRootResource.java | 30 +++++++++++++ .../welcome/SsoLogoutWelcomePlugin.java | 36 ++++++++++++++++ .../SsoLogoutWelcomePluginRootResource.java | 30 +++++++++++++ ...g.camunda.bpm.admin.plugin.spi.AdminPlugin | 1 + ...munda.bpm.cockpit.plugin.spi.CockpitPlugin | 1 + ...nda.bpm.tasklist.plugin.spi.TasklistPlugin | 1 + ...munda.bpm.welcome.plugin.spi.WelcomePlugin | 1 + .../sso-logout-plugin/app/plugin.css | 0 .../sso-logout-plugin/app/plugin.js | 42 +++++++++++++++++++ 16 files changed, 333 insertions(+), 1 deletion(-) create mode 100644 spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/SsoLogoutPluginConstants.java create mode 100644 spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/admin/SsoLogoutAdminPlugin.java create mode 100644 spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/admin/SsoLogoutAdminPluginRootResource.java create mode 100644 spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/cockpit/SsoLogoutCockpitPlugin.java create mode 100644 spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/cockpit/SsoLogoutCockpitPluginRootResource.java create mode 100644 spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/tasklist/SsoLogoutTasklistPlugin.java create mode 100644 spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/tasklist/SsoLogoutTasklistPluginRootResource.java create mode 100644 spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/welcome/SsoLogoutWelcomePlugin.java create mode 100644 spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/welcome/SsoLogoutWelcomePluginRootResource.java create mode 100644 spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.admin.plugin.spi.AdminPlugin create mode 100644 spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.cockpit.plugin.spi.CockpitPlugin create mode 100644 spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.tasklist.plugin.spi.TasklistPlugin create mode 100644 spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.welcome.plugin.spi.WelcomePlugin create mode 100644 spring-boot-starter/starter-security/src/main/resources/plugin-webapp/sso-logout-plugin/app/plugin.css create mode 100644 spring-boot-starter/starter-security/src/main/resources/plugin-webapp/sso-logout-plugin/app/plugin.js diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java index a9b69bed133..ce1f8dc1b0b 100644 --- a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java @@ -127,7 +127,6 @@ public SecurityFilterChain filterChain(HttpSecurity http, .oidcLogout(c -> c.backChannel(Customizer.withDefaults())) .oauth2Login(Customizer.withDefaults()) .logout(c -> c - //.logoutUrl("") .clearAuthentication(true) .invalidateHttpSession(true) ) diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/SsoLogoutPluginConstants.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/SsoLogoutPluginConstants.java new file mode 100644 index 00000000000..b5b7552707f --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/SsoLogoutPluginConstants.java @@ -0,0 +1,23 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; 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.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin; + +public class SsoLogoutPluginConstants { + + public static final String ID = "sso-logout-plugin"; + +} diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/admin/SsoLogoutAdminPlugin.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/admin/SsoLogoutAdminPlugin.java new file mode 100644 index 00000000000..2701e4bc294 --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/admin/SsoLogoutAdminPlugin.java @@ -0,0 +1,36 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; 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.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.admin; + +import org.camunda.bpm.admin.plugin.spi.impl.AbstractAdminPlugin; +import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.SsoLogoutPluginConstants; + +import java.util.Set; + +public class SsoLogoutAdminPlugin extends AbstractAdminPlugin { + + @Override + public Set> getResourceClasses() { + return Set.of(SsoLogoutAdminPluginRootResource.class); + } + + @Override + public String getId() { + return SsoLogoutPluginConstants.ID; + } + +} diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/admin/SsoLogoutAdminPluginRootResource.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/admin/SsoLogoutAdminPluginRootResource.java new file mode 100644 index 00000000000..8b2fb7d3f3b --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/admin/SsoLogoutAdminPluginRootResource.java @@ -0,0 +1,30 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; 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.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.admin; + +import jakarta.ws.rs.Path; +import org.camunda.bpm.admin.resource.AbstractAdminPluginRootResource; +import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.SsoLogoutPluginConstants; + +@Path("plugin/" + SsoLogoutPluginConstants.ID) +public class SsoLogoutAdminPluginRootResource extends AbstractAdminPluginRootResource { + + public SsoLogoutAdminPluginRootResource() { + super(SsoLogoutPluginConstants.ID); + } + +} diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/cockpit/SsoLogoutCockpitPlugin.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/cockpit/SsoLogoutCockpitPlugin.java new file mode 100644 index 00000000000..473d6600274 --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/cockpit/SsoLogoutCockpitPlugin.java @@ -0,0 +1,36 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; 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.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.cockpit; + +import org.camunda.bpm.cockpit.plugin.spi.impl.AbstractCockpitPlugin; +import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.SsoLogoutPluginConstants; + +import java.util.Set; + +public class SsoLogoutCockpitPlugin extends AbstractCockpitPlugin { + + @Override + public Set> getResourceClasses() { + return Set.of(SsoLogoutCockpitPluginRootResource.class); + } + + @Override + public String getId() { + return SsoLogoutPluginConstants.ID; + } + +} diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/cockpit/SsoLogoutCockpitPluginRootResource.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/cockpit/SsoLogoutCockpitPluginRootResource.java new file mode 100644 index 00000000000..5ebd23ba46b --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/cockpit/SsoLogoutCockpitPluginRootResource.java @@ -0,0 +1,30 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; 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.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.cockpit; + +import jakarta.ws.rs.Path; +import org.camunda.bpm.cockpit.plugin.resource.AbstractCockpitPluginRootResource; +import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.SsoLogoutPluginConstants; + +@Path("plugin/" + SsoLogoutPluginConstants.ID) +public class SsoLogoutCockpitPluginRootResource extends AbstractCockpitPluginRootResource { + + public SsoLogoutCockpitPluginRootResource() { + super(SsoLogoutPluginConstants.ID); + } + +} diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/tasklist/SsoLogoutTasklistPlugin.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/tasklist/SsoLogoutTasklistPlugin.java new file mode 100644 index 00000000000..8e2f34dabbb --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/tasklist/SsoLogoutTasklistPlugin.java @@ -0,0 +1,36 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; 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.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.tasklist; + +import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.SsoLogoutPluginConstants; +import org.camunda.bpm.tasklist.plugin.spi.impl.AbstractTasklistPlugin; + +import java.util.Set; + +public class SsoLogoutTasklistPlugin extends AbstractTasklistPlugin { + + @Override + public Set> getResourceClasses() { + return Set.of(SsoLogoutTasklistPluginRootResource.class); + } + + @Override + public String getId() { + return SsoLogoutPluginConstants.ID; + } + +} diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/tasklist/SsoLogoutTasklistPluginRootResource.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/tasklist/SsoLogoutTasklistPluginRootResource.java new file mode 100644 index 00000000000..da576444610 --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/tasklist/SsoLogoutTasklistPluginRootResource.java @@ -0,0 +1,30 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; 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.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.tasklist; + +import jakarta.ws.rs.Path; +import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.SsoLogoutPluginConstants; +import org.camunda.bpm.tasklist.resource.AbstractTasklistPluginRootResource; + +@Path("plugin/" + SsoLogoutPluginConstants.ID) +public class SsoLogoutTasklistPluginRootResource extends AbstractTasklistPluginRootResource { + + public SsoLogoutTasklistPluginRootResource() { + super(SsoLogoutPluginConstants.ID); + } + +} diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/welcome/SsoLogoutWelcomePlugin.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/welcome/SsoLogoutWelcomePlugin.java new file mode 100644 index 00000000000..bb5174ea5ff --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/welcome/SsoLogoutWelcomePlugin.java @@ -0,0 +1,36 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; 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.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.welcome; + +import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.SsoLogoutPluginConstants; +import org.camunda.bpm.welcome.plugin.spi.impl.AbstractWelcomePlugin; + +import java.util.Set; + +public class SsoLogoutWelcomePlugin extends AbstractWelcomePlugin { + + @Override + public Set> getResourceClasses() { + return Set.of(SsoLogoutWelcomePluginRootResource.class); + } + + @Override + public String getId() { + return SsoLogoutPluginConstants.ID; + } + +} diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/welcome/SsoLogoutWelcomePluginRootResource.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/welcome/SsoLogoutWelcomePluginRootResource.java new file mode 100644 index 00000000000..e5d7683eae4 --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/plugin/welcome/SsoLogoutWelcomePluginRootResource.java @@ -0,0 +1,30 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; 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.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.welcome; + +import jakarta.ws.rs.Path; +import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.SsoLogoutPluginConstants; +import org.camunda.bpm.welcome.resource.AbstractWelcomePluginRootResource; + +@Path("plugin/" + SsoLogoutPluginConstants.ID) +public class SsoLogoutWelcomePluginRootResource extends AbstractWelcomePluginRootResource { + + public SsoLogoutWelcomePluginRootResource() { + super(SsoLogoutPluginConstants.ID); + } + +} diff --git a/spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.admin.plugin.spi.AdminPlugin b/spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.admin.plugin.spi.AdminPlugin new file mode 100644 index 00000000000..95293748a06 --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.admin.plugin.spi.AdminPlugin @@ -0,0 +1 @@ +org.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.admin.SsoLogoutAdminPlugin \ No newline at end of file diff --git a/spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.cockpit.plugin.spi.CockpitPlugin b/spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.cockpit.plugin.spi.CockpitPlugin new file mode 100644 index 00000000000..618641f8a9e --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.cockpit.plugin.spi.CockpitPlugin @@ -0,0 +1 @@ +org.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.cockpit.SsoLogoutCockpitPlugin \ No newline at end of file diff --git a/spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.tasklist.plugin.spi.TasklistPlugin b/spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.tasklist.plugin.spi.TasklistPlugin new file mode 100644 index 00000000000..3113913ff52 --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.tasklist.plugin.spi.TasklistPlugin @@ -0,0 +1 @@ +org.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.tasklist.SsoLogoutTasklistPlugin \ No newline at end of file diff --git a/spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.welcome.plugin.spi.WelcomePlugin b/spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.welcome.plugin.spi.WelcomePlugin new file mode 100644 index 00000000000..50287096eae --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/resources/META-INF/services/org.camunda.bpm.welcome.plugin.spi.WelcomePlugin @@ -0,0 +1 @@ +org.camunda.bpm.spring.boot.starter.security.oauth2.impl.plugin.welcome.SsoLogoutWelcomePlugin \ No newline at end of file diff --git a/spring-boot-starter/starter-security/src/main/resources/plugin-webapp/sso-logout-plugin/app/plugin.css b/spring-boot-starter/starter-security/src/main/resources/plugin-webapp/sso-logout-plugin/app/plugin.css new file mode 100644 index 00000000000..e69de29bb2d diff --git a/spring-boot-starter/starter-security/src/main/resources/plugin-webapp/sso-logout-plugin/app/plugin.js b/spring-boot-starter/starter-security/src/main/resources/plugin-webapp/sso-logout-plugin/app/plugin.js new file mode 100644 index 00000000000..c504b216baf --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/resources/plugin-webapp/sso-logout-plugin/app/plugin.js @@ -0,0 +1,42 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; 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. + */ + +// observe document if logout link is rendered and override it for SSO logout +const observer = new MutationObserver(() => { + const logoutListItem = document.querySelector("li.account li.logout"); + if (logoutListItem) { + observer.disconnect(); + + const oldLogoutLink = logoutListItem.getElementsByTagName("a")[0]; + // create a clone so no listeners are attached anymore + const logoutLink = oldLogoutLink.cloneNode(true); + logoutListItem.replaceChild(logoutLink, oldLogoutLink); + + // find out the base url, i.e. the part until app-root + const appRoot = document.querySelector("base").getAttribute("app-root"); + const idx = document.location.href.indexOf(appRoot); + const baseUrl = document.location.href.substring(0, idx); + + logoutLink.href = baseUrl + "/logout"; + } +}); +observer.observe(document, { attributes: false, childList: true, characterData: false, subtree: true }); + +// forward user from login page to dashboard +if (window.location.hash.includes("login")) { + window.location.hash = ""; +} \ No newline at end of file From b87833bec26f2e99994b3fa84674e1475bc00d7b Mon Sep 17 00:00:00 2001 From: Daniel Kelemen Date: Wed, 18 Sep 2024 15:05:04 +0200 Subject: [PATCH 3/5] fix login hash detection --- .../resources/plugin-webapp/sso-logout-plugin/app/plugin.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spring-boot-starter/starter-security/src/main/resources/plugin-webapp/sso-logout-plugin/app/plugin.js b/spring-boot-starter/starter-security/src/main/resources/plugin-webapp/sso-logout-plugin/app/plugin.js index c504b216baf..e823b51a64a 100644 --- a/spring-boot-starter/starter-security/src/main/resources/plugin-webapp/sso-logout-plugin/app/plugin.js +++ b/spring-boot-starter/starter-security/src/main/resources/plugin-webapp/sso-logout-plugin/app/plugin.js @@ -36,7 +36,7 @@ const observer = new MutationObserver(() => { }); observer.observe(document, { attributes: false, childList: true, characterData: false, subtree: true }); -// forward user from login page to dashboard -if (window.location.hash.includes("login")) { +// on page load forward user from login page to dashboard +if (window.location.hash === '#/login') { window.location.hash = ""; } \ No newline at end of file From f51fb32576653351fe9a06197cc27e6358aed9ab Mon Sep 17 00:00:00 2001 From: Daniel Kelemen Date: Thu, 19 Sep 2024 10:57:49 +0200 Subject: [PATCH 4/5] update imports order after rebase --- .../oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java index ce1f8dc1b0b..410a4c5831a 100644 --- a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java @@ -45,9 +45,9 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; import org.springframework.security.oauth2.client.oidc.web.logout.OidcClientInitiatedLogoutSuccessHandler; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; From b6a227f8f5e258d0c3d0f5d517c66aff84237a42 Mon Sep 17 00:00:00 2001 From: Daniel Kelemen Date: Thu, 19 Sep 2024 14:18:23 +0200 Subject: [PATCH 5/5] add logging in sso logout, extend spring class --- ...SpringSecurityOAuth2AutoConfiguration.java | 33 +++++++------ .../oauth2/impl/SsoLogoutSuccessHandler.java | 46 +++++++++++++++++++ 2 files changed, 65 insertions(+), 14 deletions(-) create mode 100644 spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/SsoLogoutSuccessHandler.java diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java index 410a4c5831a..3afb6e4b6a5 100644 --- a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/CamundaSpringSecurityOAuth2AutoConfiguration.java @@ -16,6 +16,7 @@ */ package org.camunda.bpm.spring.boot.starter.security.oauth2; +import jakarta.annotation.Nullable; import jakarta.servlet.DispatcherType; import jakarta.servlet.Filter; import org.camunda.bpm.engine.rest.security.auth.ProcessEngineAuthenticationFilter; @@ -27,6 +28,7 @@ import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.OAuth2AuthenticationProvider; import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.OAuth2GrantedAuthoritiesMapper; import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.OAuth2IdentityProviderPlugin; +import org.camunda.bpm.spring.boot.starter.security.oauth2.impl.SsoLogoutSuccessHandler; import org.camunda.bpm.webapp.impl.security.auth.ContainerBasedAuthenticationFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -46,11 +48,9 @@ import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper; import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager; -import org.springframework.security.oauth2.client.oidc.web.logout.OidcClientInitiatedLogoutSuccessHandler; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter; import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.authentication.logout.LogoutSuccessHandler; import java.util.Map; @@ -88,7 +88,7 @@ public FilterRegistrationBean webappAuthenticationFilter() { } @Bean - @ConditionalOnProperty(name = "identity-provider.enabled", prefix = OAuth2Properties.PREFIX) + @ConditionalOnProperty(name = "identity-provider.enabled", havingValue = "true", prefix = OAuth2Properties.PREFIX) public OAuth2IdentityProviderPlugin identityProviderPlugin() { logger.debug("Registering OAuth2IdentityProviderPlugin"); return new OAuth2IdentityProviderPlugin(); @@ -101,20 +101,25 @@ protected GrantedAuthoritiesMapper grantedAuthoritiesMapper() { return new OAuth2GrantedAuthoritiesMapper(oAuth2Properties); } - protected LogoutSuccessHandler oidcLogoutSuccessHandler(ClientRegistrationRepository clientRegistrationRepository) { - var oidcLogoutSuccessHandler = new OidcClientInitiatedLogoutSuccessHandler(clientRegistrationRepository); - // Redirected after the logout has been performed at the provider - oidcLogoutSuccessHandler.setPostLogoutRedirectUri(oAuth2Properties.getSsoLogout().getPostLogoutRedirectUri()); - return oidcLogoutSuccessHandler; + @Bean + @ConditionalOnProperty(name = "sso-logout.enabled", havingValue = "true", prefix = OAuth2Properties.PREFIX) + protected SsoLogoutSuccessHandler ssoLogoutSuccessHandler(ClientRegistrationRepository clientRegistrationRepository) { + logger.debug("Registering SsoLogoutSuccessHandler"); + return new SsoLogoutSuccessHandler(clientRegistrationRepository, oAuth2Properties); + } + + @Bean + protected AuthorizeTokenFilter authorizeTokenFilter(OAuth2AuthorizedClientManager clientManager) { + logger.debug("Registering AuthorizeTokenFilter"); + return new AuthorizeTokenFilter(clientManager); } @Bean public SecurityFilterChain filterChain(HttpSecurity http, - ClientRegistrationRepository clientRegistrationRepository, - OAuth2AuthorizedClientManager clientManager) throws Exception { - logger.info("Enabling Camunda Spring Security oauth2 integration"); + AuthorizeTokenFilter authorizeTokenFilter, + @Nullable SsoLogoutSuccessHandler ssoLogoutSuccessHandler) throws Exception { - var validateTokenFilter = new AuthorizeTokenFilter(clientManager); + logger.info("Enabling Camunda Spring Security oauth2 integration"); // @formatter:off http.authorizeHttpRequests(c -> c @@ -122,7 +127,7 @@ public SecurityFilterChain filterChain(HttpSecurity http, .requestMatchers(webappPath + "/api/**").authenticated() .anyRequest().permitAll() ) - .addFilterAfter(validateTokenFilter, OAuth2AuthorizationRequestRedirectFilter.class) + .addFilterAfter(authorizeTokenFilter, OAuth2AuthorizationRequestRedirectFilter.class) .anonymous(AbstractHttpConfigurer::disable) .oidcLogout(c -> c.backChannel(Customizer.withDefaults())) .oauth2Login(Customizer.withDefaults()) @@ -136,7 +141,7 @@ public SecurityFilterChain filterChain(HttpSecurity http, // @formatter:on if (oAuth2Properties.getSsoLogout().isEnabled()) { - http.logout(c -> c.logoutSuccessHandler(oidcLogoutSuccessHandler(clientRegistrationRepository))); + http.logout(c -> c.logoutSuccessHandler(ssoLogoutSuccessHandler)); } return http.build(); diff --git a/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/SsoLogoutSuccessHandler.java b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/SsoLogoutSuccessHandler.java new file mode 100644 index 00000000000..09669566ae4 --- /dev/null +++ b/spring-boot-starter/starter-security/src/main/java/org/camunda/bpm/spring/boot/starter/security/oauth2/impl/SsoLogoutSuccessHandler.java @@ -0,0 +1,46 @@ +/* + * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH + * under one or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information regarding copyright + * ownership. Camunda licenses this file to you under the Apache License, + * Version 2.0; 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.camunda.bpm.spring.boot.starter.security.oauth2.impl; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.camunda.bpm.spring.boot.starter.security.oauth2.OAuth2Properties; +import org.springframework.security.core.Authentication; +import org.springframework.security.oauth2.client.oidc.web.logout.OidcClientInitiatedLogoutSuccessHandler; +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; + +import java.io.IOException; + +/** + * {@link OidcClientInitiatedLogoutSuccessHandler} with logging. + */ +public class SsoLogoutSuccessHandler extends OidcClientInitiatedLogoutSuccessHandler { + + public SsoLogoutSuccessHandler(ClientRegistrationRepository clientRegistrationRepository, + OAuth2Properties oAuth2Properties) { + super(clientRegistrationRepository); + this.setPostLogoutRedirectUri(oAuth2Properties.getSsoLogout().getPostLogoutRedirectUri()); + } + + @Override + public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) + throws IOException, ServletException { + logger.debug("Initiating SSO logout with provider."); + super.onLogoutSuccess(request, response, authentication); + } +}