From 0d7d245703bd8dec5d7a586cf1fc323a4e73aa5c Mon Sep 17 00:00:00 2001 From: Pavel Kotelevsky Date: Mon, 6 Mar 2023 18:12:27 +0100 Subject: [PATCH] feat(bundle-saas): support m2m authentication in SaaS --- bundle/mvn/camunda-saas-bundle/pom.xml | 4 ++ .../runtime/security/AudienceValidator.java | 23 ++++++++ .../security/SecurityConfiguration.java | 57 +++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 bundle/mvn/camunda-saas-bundle/src/main/java/io/camunda/connector/runtime/security/AudienceValidator.java create mode 100644 bundle/mvn/camunda-saas-bundle/src/main/java/io/camunda/connector/runtime/security/SecurityConfiguration.java diff --git a/bundle/mvn/camunda-saas-bundle/pom.xml b/bundle/mvn/camunda-saas-bundle/pom.xml index b2696db1f2..3accc637f8 100644 --- a/bundle/mvn/camunda-saas-bundle/pom.xml +++ b/bundle/mvn/camunda-saas-bundle/pom.xml @@ -16,6 +16,10 @@ connector-runtime-bundle ${project.version} + + org.springframework.boot + spring-boot-starter-oauth2-resource-server + io.camunda.connector connector-gcp-security-manager diff --git a/bundle/mvn/camunda-saas-bundle/src/main/java/io/camunda/connector/runtime/security/AudienceValidator.java b/bundle/mvn/camunda-saas-bundle/src/main/java/io/camunda/connector/runtime/security/AudienceValidator.java new file mode 100644 index 0000000000..f5a478d29e --- /dev/null +++ b/bundle/mvn/camunda-saas-bundle/src/main/java/io/camunda/connector/runtime/security/AudienceValidator.java @@ -0,0 +1,23 @@ +package io.camunda.connector.runtime.security; + +import org.springframework.security.oauth2.core.OAuth2Error; +import org.springframework.security.oauth2.core.OAuth2TokenValidator; +import org.springframework.security.oauth2.core.OAuth2TokenValidatorResult; +import org.springframework.security.oauth2.jwt.Jwt; + +public class AudienceValidator implements OAuth2TokenValidator { + private final String audience; + + AudienceValidator(String audience) { + this.audience = audience; + } + + public OAuth2TokenValidatorResult validate(Jwt jwt) { + OAuth2Error error = new OAuth2Error("invalid_token", "The required audience is missing", null); + + if (jwt.getAudience().contains(audience)) { + return OAuth2TokenValidatorResult.success(); + } + return OAuth2TokenValidatorResult.failure(error); + } +} diff --git a/bundle/mvn/camunda-saas-bundle/src/main/java/io/camunda/connector/runtime/security/SecurityConfiguration.java b/bundle/mvn/camunda-saas-bundle/src/main/java/io/camunda/connector/runtime/security/SecurityConfiguration.java new file mode 100644 index 0000000000..b349c712cc --- /dev/null +++ b/bundle/mvn/camunda-saas-bundle/src/main/java/io/camunda/connector/runtime/security/SecurityConfiguration.java @@ -0,0 +1,57 @@ +package io.camunda.connector.runtime.security; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator; +import org.springframework.security.oauth2.core.OAuth2TokenValidator; +import org.springframework.security.oauth2.jwt.Jwt; +import org.springframework.security.oauth2.jwt.JwtDecoder; +import org.springframework.security.oauth2.jwt.JwtDecoders; +import org.springframework.security.oauth2.jwt.JwtValidators; +import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; +import org.springframework.security.web.SecurityFilterChain; + +@EnableWebSecurity +@Configuration +public class SecurityConfiguration { + + @Value("${camunda.connector.auth.audience}") + private String audience; + + @Value("${camunda.connector.auth.issuer}") + private String issuer; + + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + http.csrf() + .disable() + .authorizeRequests() + .antMatchers(HttpMethod.POST, "/inbound/**") + .permitAll() + .antMatchers("/inbound") + .hasAuthority("SCOPE_inbound:read") + .anyRequest() + .authenticated() + .and() + .oauth2ResourceServer() + .jwt(); + return http.build(); + } + + @Bean + JwtDecoder jwtDecoder() { + NimbusJwtDecoder jwtDecoder = JwtDecoders.fromOidcIssuerLocation(issuer); + + OAuth2TokenValidator audienceValidator = new AudienceValidator(audience); + OAuth2TokenValidator withIssuer = JwtValidators.createDefaultWithIssuer(issuer); + OAuth2TokenValidator withAudience = + new DelegatingOAuth2TokenValidator<>(withIssuer, audienceValidator); + + jwtDecoder.setJwtValidator(withAudience); + return jwtDecoder; + } +}