Skip to content

Commit

Permalink
Add the ability to trust self-signed certificates from authorization …
Browse files Browse the repository at this point in the history
…server. (#9)
  • Loading branch information
dzarras authored Nov 17, 2023
1 parent 2e3648b commit 4029c2c
Show file tree
Hide file tree
Showing 3 changed files with 128 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import eu.europa.ec.eudi.pidissuer.adapter.out.jose.EncryptCredentialResponseWit
import eu.europa.ec.eudi.pidissuer.adapter.out.persistence.InMemoryCNonceRepository
import eu.europa.ec.eudi.pidissuer.adapter.out.persistence.InMemoryDeferredCredentialRepository
import eu.europa.ec.eudi.pidissuer.adapter.out.pid.*
import eu.europa.ec.eudi.pidissuer.adapter.out.webclient.WebClients
import eu.europa.ec.eudi.pidissuer.domain.*
import eu.europa.ec.eudi.pidissuer.port.input.GetCredentialIssuerMetaData
import eu.europa.ec.eudi.pidissuer.port.input.GetDeferredCredential
Expand All @@ -42,6 +43,7 @@ import eu.europa.ec.eudi.sdjwt.HashAlgorithm
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.autoconfigure.security.oauth2.resource.OAuth2ResourceServerProperties
import org.springframework.boot.runApplication
import org.springframework.context.ApplicationContextInitializer
import org.springframework.context.support.BeanDefinitionDsl
Expand All @@ -57,6 +59,7 @@ import org.springframework.http.codec.json.KotlinSerializationJsonEncoder
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity
import org.springframework.security.config.web.server.ServerHttpSecurity
import org.springframework.security.config.web.server.invoke
import org.springframework.security.oauth2.server.resource.introspection.SpringReactiveOpaqueTokenIntrospector
import org.springframework.security.web.server.authentication.HttpStatusServerEntryPoint
import org.springframework.web.reactive.config.EnableWebFlux
import org.springframework.web.reactive.config.WebFluxConfigurer
Expand All @@ -68,12 +71,23 @@ fun beans(clock: Clock) = beans {
// Adapters (out ports)
//
bean { clock }
bean {
GetPidDataFromAuthServer(
env.readRequiredUrl("issuer.authorizationServer.userinfo"),
env.getRequiredProperty("issuer.pid.issuingCountry").let(::IsoCountry),
clock,
)
profile("!insecure") {
bean {
GetPidDataFromAuthServer(
env.readRequiredUrl("issuer.authorizationServer.userinfo"),
env.getRequiredProperty("issuer.pid.issuingCountry").let(::IsoCountry),
clock,
)
}
}
profile("insecure") {
bean {
GetPidDataFromAuthServer.insecure(
env.readRequiredUrl("issuer.authorizationServer.userinfo"),
env.getRequiredProperty("issuer.pid.issuingCountry").let(::IsoCountry),
clock,
)
}
}
//
// Encryption of credential response
Expand Down Expand Up @@ -196,6 +210,20 @@ fun beans(clock: Clock) = beans {
//
// Security
//
profile("insecure") {
bean {
val properties = ref<OAuth2ResourceServerProperties>()

SpringReactiveOpaqueTokenIntrospector(
properties.opaquetoken.introspectionUri,
WebClients.insecure {
defaultHeaders {
it.setBasicAuth(properties.opaquetoken.clientId, properties.opaquetoken.clientSecret)
}
},
)
}
}
bean {
/*
* This is a Spring naming convention
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ package eu.europa.ec.eudi.pidissuer.adapter.out.pid

import eu.europa.ec.eudi.pidissuer.adapter.out.oauth.OidcAddressClaim
import eu.europa.ec.eudi.pidissuer.adapter.out.oauth.OidcAssurancePlaceOfBirth
import eu.europa.ec.eudi.pidissuer.adapter.out.webclient.WebClients
import eu.europa.ec.eudi.pidissuer.domain.HttpsUrl
import kotlinx.serialization.Required
import kotlinx.serialization.SerialName
Expand All @@ -32,17 +33,15 @@ import java.time.LocalDate

private val log = LoggerFactory.getLogger(GetPidDataFromAuthServer::class.java)

class GetPidDataFromAuthServer(
authorizationServerUserInfoEndPoint: HttpsUrl,
class GetPidDataFromAuthServer private constructor(
private val issuerCountry: IsoCountry,
private val clock: Clock,
private val webClient: WebClient,
) : GetPidData {

private val jsonSupport: Json by lazy {
Json { prettyPrint = true }
}
private val webClient: WebClient =
WebClient.create(authorizationServerUserInfoEndPoint.externalForm)

override suspend fun invoke(accessToken: String): Pair<Pid, PidMetaData>? {
log.info("Trying to get PID Data from userinfo endpoint ...")
Expand Down Expand Up @@ -94,6 +93,42 @@ class GetPidDataFromAuthServer(

return pid to pidMetaData
}

companion object {

/**
* Creates a new [GetPidDataFromAuthServer] using the provided data.
*/
operator fun invoke(
authorizationServerUserInfoEndPoint: HttpsUrl,
issuerCountry: IsoCountry,
clock: Clock,
): GetPidDataFromAuthServer =
GetPidDataFromAuthServer(
issuerCountry,
clock,
WebClients.default {
baseUrl(authorizationServerUserInfoEndPoint.externalForm)
},
)

/**
* Creates a new *insecure* [GetPidDataFromAuthServer] that trusts all certificates.
*/
fun insecure(
authorizationServerUserInfoEndPoint: HttpsUrl,
issuerCountry: IsoCountry,
clock: Clock,
): GetPidDataFromAuthServer {
return GetPidDataFromAuthServer(
issuerCountry,
clock,
WebClients.insecure {
baseUrl(authorizationServerUserInfoEndPoint.externalForm)
},
)
}
}
}

@Serializable
Expand All @@ -105,7 +140,7 @@ private data class UserInfo(
@SerialName(OidcAddressClaim.NAME) val address: OidcAddressClaim? = null,
@SerialName("birthdate") val birthDate: String? = null,
@SerialName("gender") val gender: UInt? = null,
@SerialName(OidcAssurancePlaceOfBirth.NAME)val placeOfBirth: OidcAssurancePlaceOfBirth? = null,
@SerialName(OidcAssurancePlaceOfBirth.NAME) val placeOfBirth: OidcAssurancePlaceOfBirth? = null,
@SerialName("age_over_18") val ageOver18: Boolean? = null,
val profile: String? = null,
val picture: String? = null,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright (c) 2023 European Commission
*
* Licensed under the Apache License, Version 2.0 (the "License");
* 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 eu.europa.ec.eudi.pidissuer.adapter.out.webclient

import io.netty.handler.ssl.SslContextBuilder
import io.netty.handler.ssl.util.InsecureTrustManagerFactory
import org.slf4j.LoggerFactory
import org.springframework.http.client.reactive.ReactorClientHttpConnector
import org.springframework.web.reactive.function.client.WebClient
import reactor.netty.http.client.HttpClient

private val log = LoggerFactory.getLogger(WebClients::class.java)

/**
* Factories for [WebClient].
*/
internal object WebClients {

/**
* Creates a new [WebClient].
*/
fun default(customizer: WebClient.Builder.() -> Unit = {}): WebClient =
WebClient.builder()
.apply(customizer)
.build()

/**
* Creates an *insecure* [WebClient] that trusts all certificates.
*/
fun insecure(customizer: WebClient.Builder.() -> Unit = {}): WebClient {
log.warn("Using insecure WebClient trusting all certificates")
val sslContext = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE)
.build()
val httpClient = HttpClient.create().secure { it.sslContext(sslContext) }
return WebClient.builder()
.clientConnector(ReactorClientHttpConnector(httpClient))
.apply(customizer)
.build()
}
}

0 comments on commit 4029c2c

Please sign in to comment.