diff --git a/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/BpdmSecurityConfigurerAdapterImpl.kt b/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/BpdmSecurityConfigurerAdapterImpl.kt new file mode 100644 index 000000000..eff0ac21c --- /dev/null +++ b/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/BpdmSecurityConfigurerAdapterImpl.kt @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2021,2023 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://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. + * + * SPDX-License-Identifier: Apache-2.0 + ******************************************************************************/ + +package com.catenax.bpdm.bridge.dummy.config + +import org.eclipse.tractusx.bpdm.common.config.BpdmSecurityConfigurerAdapter +import org.eclipse.tractusx.bpdm.common.config.CustomJwtAuthenticationConverter +import org.eclipse.tractusx.bpdm.common.config.SecurityConfigProperties +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.http.SessionCreationPolicy +import org.springframework.security.web.util.matcher.AntPathRequestMatcher + +@Configuration +class BpdmSecurityConfigurerAdapterImpl( + val securityConfigProperties: SecurityConfigProperties +) : BpdmSecurityConfigurerAdapter { + override fun configure(http: HttpSecurity) { + http.csrf().disable() + http.cors() + http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + http.authorizeHttpRequests() + .requestMatchers(AntPathRequestMatcher("/api/**", HttpMethod.OPTIONS.name())).permitAll() + .requestMatchers(AntPathRequestMatcher("/")).permitAll() // forwards to swagger + .requestMatchers(AntPathRequestMatcher("/docs/api-docs/**")).permitAll() + .requestMatchers(AntPathRequestMatcher("/ui/swagger-ui/**")).permitAll() + .requestMatchers(AntPathRequestMatcher("/actuator/health/**")).permitAll() + .requestMatchers(AntPathRequestMatcher("/error")).permitAll() + .requestMatchers(AntPathRequestMatcher("/api/**")).authenticated() + http.oauth2ResourceServer() + .jwt() + .jwtAuthenticationConverter(CustomJwtAuthenticationConverter(securityConfigProperties.clientId)) + } +} \ No newline at end of file diff --git a/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/ClientsConfig.kt b/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/ClientsConfig.kt index 0f904adea..e06d73a09 100644 --- a/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/ClientsConfig.kt +++ b/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/ClientsConfig.kt @@ -26,12 +26,22 @@ import org.eclipse.tractusx.bpdm.pool.api.client.PoolClientImpl import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration +import org.springframework.http.HttpHeaders +import org.springframework.http.MediaType +import org.springframework.security.oauth2.client.AuthorizedClientServiceOAuth2AuthorizedClientManager +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientManager +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientProviderBuilder +import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService +import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository +import org.springframework.security.oauth2.client.web.reactive.function.client.ServletOAuth2AuthorizedClientExchangeFilterFunction import org.springframework.web.reactive.function.client.WebClient +import java.util.function.Consumer @Configuration class ClientsConfig { + // Pool-Client without authentication @Bean @ConditionalOnProperty( value = ["bpdm.pool.security-enabled"], @@ -40,9 +50,10 @@ class ClientsConfig { ) fun poolClientNoAuth(poolConfigProperties: PoolConfigProperties): PoolApiClient { val url = poolConfigProperties.baseUrl - return PoolClientImpl { WebClient.create(url) } + return PoolClientImpl { webClientBuilder(url).build() } } + // Gate-Client without authentication @Bean @ConditionalOnProperty( value = ["bpdm.gate.security-enabled"], @@ -51,9 +62,75 @@ class ClientsConfig { ) fun gateClientNoAuth(gateConfigProperties: GateConfigProperties): GateClient { val url = gateConfigProperties.baseUrl - return GateClientImpl { WebClient.create(url) } + return GateClientImpl { webClientBuilder(url).build() } } - // TODO add clients with authentication enabled + // Pool-Client with OAuth2 authentication + @Bean + @ConditionalOnProperty( + value = ["bpdm.pool.security-enabled"], + havingValue = "true" + ) + fun poolClientWithAuth( + poolConfigProperties: PoolConfigProperties, + clientRegistrationRepository: ClientRegistrationRepository, + authorizedClientService: OAuth2AuthorizedClientService + ): PoolApiClient { + val url = poolConfigProperties.baseUrl + val clientRegistrationId = poolConfigProperties.oauth2ClientRegistration + ?: throw IllegalArgumentException("bpdm.pool.oauth2-client-registration is required if bpdm.pool.security-enabled is set") + return PoolClientImpl { + webClientBuilder(url) + .apply(oauth2Configuration(clientRegistrationRepository, authorizedClientService, clientRegistrationId)) + .build() + } + } + + // Gate-Client with OAuth2 authentication + @Bean + @ConditionalOnProperty( + value = ["bpdm.gate.security-enabled"], + havingValue = "true" + ) + fun gateClientWithAuth( + gateConfigProperties: GateConfigProperties, + clientRegistrationRepository: ClientRegistrationRepository, + authorizedClientService: OAuth2AuthorizedClientService + ): GateClient { + val url = gateConfigProperties.baseUrl + val clientRegistrationId = gateConfigProperties.oauth2ClientRegistration + ?: throw IllegalArgumentException("bpdm.gate.oauth2-client-registration is required if bpdm.gate.security-enabled is set") + return GateClientImpl { + webClientBuilder(url) + .apply(oauth2Configuration(clientRegistrationRepository, authorizedClientService, clientRegistrationId)) + .build() + } + } + + private fun webClientBuilder(url: String) = + WebClient.builder() + .baseUrl(url) + .defaultHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE) + + private fun oauth2Configuration( + clientRegistrationRepository: ClientRegistrationRepository, + authorizedClientService: OAuth2AuthorizedClientService, + clientRegistrationId: String + ): Consumer { + val authorizedClientManager = authorizedClientManager(clientRegistrationRepository, authorizedClientService) + val oauth = ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager) + oauth.setDefaultClientRegistrationId(clientRegistrationId) + return oauth.oauth2Configuration() + } + + private fun authorizedClientManager( + clientRegistrationRepository: ClientRegistrationRepository, + authorizedClientService: OAuth2AuthorizedClientService + ): OAuth2AuthorizedClientManager { + val authorizedClientProvider = OAuth2AuthorizedClientProviderBuilder.builder().clientCredentials().build() + val authorizedClientManager = AuthorizedClientServiceOAuth2AuthorizedClientManager(clientRegistrationRepository, authorizedClientService) + authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider) + return authorizedClientManager + } } \ No newline at end of file diff --git a/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/GateConfigProperties.kt b/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/GateConfigProperties.kt index e855ea84e..c99147283 100644 --- a/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/GateConfigProperties.kt +++ b/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/GateConfigProperties.kt @@ -25,4 +25,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties @ConfigurationProperties(prefix = "bpdm.gate") data class GateConfigProperties( val baseUrl: String = "http://localhost:8081/", + val securityEnabled: Boolean = false, + val oauth2ClientRegistration: String? ) diff --git a/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/PoolConfigProperties.kt b/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/PoolConfigProperties.kt index edc213fd7..c5c13eb2b 100644 --- a/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/PoolConfigProperties.kt +++ b/bpdm-bridge-dummy/src/main/kotlin/com/catenax/bpdm/bridge/dummy/config/PoolConfigProperties.kt @@ -25,4 +25,6 @@ import org.springframework.boot.context.properties.ConfigurationProperties @ConfigurationProperties(prefix = "bpdm.pool") data class PoolConfigProperties( val baseUrl: String = "http://localhost:8080/", + val securityEnabled: Boolean = false, + val oauth2ClientRegistration: String? ) diff --git a/bpdm-bridge-dummy/src/main/resources/application-auth.properties b/bpdm-bridge-dummy/src/main/resources/application-auth.properties new file mode 100644 index 000000000..2f3c2d57d --- /dev/null +++ b/bpdm-bridge-dummy/src/main/resources/application-auth.properties @@ -0,0 +1,45 @@ +################################################################################ +# Copyright (c) 2021,2023 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License, Version 2.0 which is available at +# https://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. +# +# SPDX-License-Identifier: Apache-2.0 +################################################################################ +## +# Security config (defined in common) for restricting access to the bridge dummy resource server +bpdm.security.enabled=true +bpdm.security.cors-origins=* +# OAuth configuration +bpdm.security.client-id=BPDM_BRIDGE_DUMMY +bpdm.security.realm=master +bpdm.security.auth-server-url=http://localhost:8180 +bpdm.security.auth-url=${bpdm.security.auth-server-url}/realms/${bpdm.security.realm}/protocol/openid-connect/auth +bpdm.security.token-url=${bpdm.security.auth-server-url}/realms/${bpdm.security.realm}/protocol/openid-connect/token +bpdm.security.refresh-url=${bpdm.security.token-url} +# Spring security +spring.security.oauth2.resourceserver.jwt.issuer-uri=${bpdm.security.auth-server-url}/realms/${bpdm.security.realm} +spring.security.oauth2.resourceserver.jwt.jwk-set-uri=${bpdm.security.auth-server-url}/realms/${bpdm.security.realm}/protocol/openid-connect/certs +## +# OAuth2 authorized connection to Pool and Gate client +bpdm.pool.security-enabled=true +bpdm.pool.oauth2-client-registration=bridge-client +bpdm.gate.security-enabled=true +bpdm.gate.oauth2-client-registration=bridge-client +## Note that the oauth2-client-registration properties is NOT the client id in Keycloak but references spring.security.oauth2.client.registration +# registration "bridge-client" - can be used for both pool and gate client +spring.security.oauth2.client.registration.bridge-client.client-id=${bpdm.security.client-id} +spring.security.oauth2.client.registration.bridge-client.client-secret=${bpdm.security.credentials.secret} +spring.security.oauth2.client.registration.bridge-client.authorization-grant-type=client_credentials +spring.security.oauth2.client.registration.bridge-client.provider=catena-keycloak-provider +spring.security.oauth2.client.provider.catena-keycloak-provider.issuer-uri=${bpdm.security.auth-server-url:http://localhost:8180}/realms/${bpdm.security.realm:master}