This is an automated email from the ASF dual-hosted git repository. rcordier pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/james-project.git
commit 0d8c9fb4309cd82539ceb7658063d902cb587573 Author: Benoit TELLIER <[email protected]> AuthorDate: Mon Dec 8 14:11:29 2025 +0100 [ENHANCEMENT] OIDC SASL code refactoring - Mutualize code for choosing how code shall be validated between IMAP and SMTP - Turn OidcJwtTokenVerifier as a class - Have SASL configuration as a member in order to limit count of arguments --- protocols/api/pom.xml | 4 + .../apache/james/imap/api/process/ImapSession.java | 2 +- .../apache/james/imap/encode/FakeImapSession.java | 2 +- .../imap/processor/AuthenticateProcessor.java | 37 +-------- .../protocols/lmtp/LMTPConfigurationImpl.java | 2 +- .../james/protocols/smtp/SMTPConfiguration.java | 2 +- .../protocols/smtp/SMTPConfigurationImpl.java | 2 +- .../protocols/smtp/core/esmtp/AuthCmdHandler.java | 2 +- .../apache/james/protocols/smtp/hook/AuthHook.java | 2 +- server/protocols/jwt/pom.xml | 4 + .../org/apache/james/jwt/OidcJwtTokenVerifier.java | 55 +++++++++++-- .../apache/james/jwt}/OidcSASLConfiguration.java | 96 +++++++++++++++++++++- .../apache/james/jwt/OidcJwtTokenVerifierTest.java | 79 +++++++++++------- server/protocols/protocols-imap4/pom.xml | 2 +- .../apache/james/imapserver/netty/IMAPServer.java | 2 +- .../james/imapserver/netty/NettyImapSession.java | 2 +- .../apache/james/lmtpserver/netty/LMTPServer.java | 2 +- server/protocols/protocols-smtp/pom.xml | 2 +- .../james/smtpserver/ConfigurationAuthHook.java | 2 +- .../james/smtpserver/UsersRepositoryAuthHook.java | 38 +-------- .../apache/james/smtpserver/netty/SMTPServer.java | 2 +- 21 files changed, 216 insertions(+), 125 deletions(-) diff --git a/protocols/api/pom.xml b/protocols/api/pom.xml index bb9f1381ea..306b6b7bfe 100644 --- a/protocols/api/pom.xml +++ b/protocols/api/pom.xml @@ -37,6 +37,10 @@ <groupId>${james.groupId}</groupId> <artifactId>james-core</artifactId> </dependency> + <dependency> + <groupId>${james.groupId}</groupId> + <artifactId>james-server-jwt</artifactId> + </dependency> <dependency> <groupId>${james.groupId}</groupId> <artifactId>testing-base</artifactId> diff --git a/protocols/imap/src/main/java/org/apache/james/imap/api/process/ImapSession.java b/protocols/imap/src/main/java/org/apache/james/imap/api/process/ImapSession.java index e55c595301..ebdce2fdba 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/api/process/ImapSession.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/api/process/ImapSession.java @@ -31,9 +31,9 @@ import javax.net.ssl.SSLSession; import org.apache.commons.text.RandomStringGenerator; import org.apache.james.core.Username; import org.apache.james.imap.api.ImapSessionState; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.mailbox.MailboxSession; import org.apache.james.protocols.api.CommandDetectionSession; -import org.apache.james.protocols.api.OidcSASLConfiguration; import org.apache.james.util.MDCBuilder; import reactor.core.publisher.Mono; diff --git a/protocols/imap/src/main/java/org/apache/james/imap/encode/FakeImapSession.java b/protocols/imap/src/main/java/org/apache/james/imap/encode/FakeImapSession.java index ed312cf463..d73af074e1 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/encode/FakeImapSession.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/encode/FakeImapSession.java @@ -34,7 +34,7 @@ import org.apache.james.imap.api.ImapSessionState; import org.apache.james.imap.api.process.ImapLineHandler; import org.apache.james.imap.api.process.ImapSession; import org.apache.james.imap.api.process.SelectedMailbox; -import org.apache.james.protocols.api.OidcSASLConfiguration; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.util.concurrent.NamedThreadFactory; import reactor.core.publisher.Mono; diff --git a/protocols/imap/src/main/java/org/apache/james/imap/processor/AuthenticateProcessor.java b/protocols/imap/src/main/java/org/apache/james/imap/processor/AuthenticateProcessor.java index 89eaa5877c..7db61a86f0 100644 --- a/protocols/imap/src/main/java/org/apache/james/imap/processor/AuthenticateProcessor.java +++ b/protocols/imap/src/main/java/org/apache/james/imap/processor/AuthenticateProcessor.java @@ -24,7 +24,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; import java.util.List; -import java.util.Optional; import java.util.stream.Collectors; import jakarta.inject.Inject; @@ -41,11 +40,10 @@ import org.apache.james.imap.message.request.AuthenticateRequest; import org.apache.james.imap.message.request.IRAuthenticateRequest; import org.apache.james.imap.message.response.AuthenticateResponse; import org.apache.james.jwt.OidcJwtTokenVerifier; -import org.apache.james.jwt.introspection.IntrospectionEndpoint; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.mailbox.MailboxManager; import org.apache.james.metrics.api.MetricFactory; import org.apache.james.protocols.api.OIDCSASLParser; -import org.apache.james.protocols.api.OidcSASLConfiguration; import org.apache.james.util.MDCBuilder; import org.apache.james.util.ReactorUtils; import org.slf4j.Logger; @@ -212,7 +210,7 @@ public class AuthenticateProcessor extends AbstractAuthProcessor<AuthenticateReq private void doOAuth(OIDCSASLParser.OIDCInitialResponse oidcInitialResponse, OidcSASLConfiguration oidcSASLConfiguration, ImapSession session, ImapRequest request, Responder responder) { - validateToken(oidcSASLConfiguration, oidcInitialResponse.getToken()) + new OidcJwtTokenVerifier(oidcSASLConfiguration).validateToken(oidcInitialResponse.getToken()) .ifPresentOrElse(authenticatedUser -> { Username associatedUser = Username.of(oidcInitialResponse.getAssociatedUser()); if (!associatedUser.equals(authenticatedUser)) { @@ -226,37 +224,6 @@ public class AuthenticateProcessor extends AbstractAuthProcessor<AuthenticateReq }, () -> manageFailureCount(session, request, responder)); } - private Optional<Username> validateToken(OidcSASLConfiguration oidcSASLConfiguration, String token) { - if (oidcSASLConfiguration.isCheckTokenByIntrospectionEndpoint()) { - return validTokenWithIntrospection(oidcSASLConfiguration, token); - } else if (oidcSASLConfiguration.isCheckTokenByUserinfoEndpoint()) { - return validTokenWithUserInfo(oidcSASLConfiguration, token); - } else { - return OidcJwtTokenVerifier.verifySignatureAndExtractClaim(token, oidcSASLConfiguration.getJwksURL(), oidcSASLConfiguration.getClaim()) - .map(Username::of); - } - } - - private static Optional<Username> validTokenWithUserInfo(OidcSASLConfiguration oidcSASLConfiguration, String token) { - return Mono.from(OidcJwtTokenVerifier.verifyWithUserinfo(token, - oidcSASLConfiguration.getJwksURL(), - oidcSASLConfiguration.getClaim(), - oidcSASLConfiguration.getUserInfoEndpoint().orElseThrow())) - .blockOptional() - .map(Username::of); - } - - private static Optional<Username> validTokenWithIntrospection(OidcSASLConfiguration oidcSASLConfiguration, String token) { - return Mono.from(OidcJwtTokenVerifier.verifyWithIntrospection(token, - oidcSASLConfiguration.getJwksURL(), - oidcSASLConfiguration.getClaim(), - oidcSASLConfiguration.getIntrospectionEndpoint() - .map(endpoint -> new IntrospectionEndpoint(endpoint, oidcSASLConfiguration.getIntrospectionEndpointAuthorization())) - .orElseThrow())) - .blockOptional() - .map(Username::of); - } - private static String extractInitialClientResponse(byte[] data) { // cut of the CRLF return new String(data, 0, data.length - 2, StandardCharsets.US_ASCII); diff --git a/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/LMTPConfigurationImpl.java b/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/LMTPConfigurationImpl.java index 0839079148..4f874e011a 100644 --- a/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/LMTPConfigurationImpl.java +++ b/protocols/lmtp/src/test/java/org/apache/james/protocols/lmtp/LMTPConfigurationImpl.java @@ -20,7 +20,7 @@ package org.apache.james.protocols.lmtp; import java.util.Optional; -import org.apache.james.protocols.api.OidcSASLConfiguration; +import org.apache.james.jwt.OidcSASLConfiguration; public class LMTPConfigurationImpl extends LMTPConfiguration { diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPConfiguration.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPConfiguration.java index ef93169705..10bffd7fea 100644 --- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPConfiguration.java +++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPConfiguration.java @@ -25,7 +25,7 @@ import java.util.Locale; import java.util.Optional; import java.util.Set; -import org.apache.james.protocols.api.OidcSASLConfiguration; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.protocols.api.ProtocolConfiguration; import com.google.common.collect.ImmutableSet; diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPConfigurationImpl.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPConfigurationImpl.java index 0d135d24b2..8da9de699d 100644 --- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPConfigurationImpl.java +++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/SMTPConfigurationImpl.java @@ -22,7 +22,7 @@ package org.apache.james.protocols.smtp; import java.util.Optional; -import org.apache.james.protocols.api.OidcSASLConfiguration; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.protocols.api.ProtocolConfigurationImpl; /** diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/AuthCmdHandler.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/AuthCmdHandler.java index 8d4436fbfc..7cf0f14abc 100644 --- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/AuthCmdHandler.java +++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/core/esmtp/AuthCmdHandler.java @@ -35,7 +35,7 @@ import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.james.core.Username; -import org.apache.james.protocols.api.OidcSASLConfiguration; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.protocols.api.Request; import org.apache.james.protocols.api.Response; import org.apache.james.protocols.api.handler.CommandHandler; diff --git a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/AuthHook.java b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/AuthHook.java index 8351eb2367..3a7234356c 100644 --- a/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/AuthHook.java +++ b/protocols/smtp/src/main/java/org/apache/james/protocols/smtp/hook/AuthHook.java @@ -19,7 +19,7 @@ package org.apache.james.protocols.smtp.hook; import org.apache.james.core.Username; -import org.apache.james.protocols.api.OidcSASLConfiguration; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.protocols.smtp.SMTPSession; /** diff --git a/server/protocols/jwt/pom.xml b/server/protocols/jwt/pom.xml index 2a3035f9bd..e014a01d60 100644 --- a/server/protocols/jwt/pom.xml +++ b/server/protocols/jwt/pom.xml @@ -32,6 +32,10 @@ <name>Apache James :: Server :: JWT</name> <dependencies> + <dependency> + <groupId>${james.groupId}</groupId> + <artifactId>james-core</artifactId> + </dependency> <dependency> <groupId>${james.groupId}</groupId> <artifactId>testing-base</artifactId> diff --git a/server/protocols/jwt/src/main/java/org/apache/james/jwt/OidcJwtTokenVerifier.java b/server/protocols/jwt/src/main/java/org/apache/james/jwt/OidcJwtTokenVerifier.java index 63124ca253..637f57de5f 100644 --- a/server/protocols/jwt/src/main/java/org/apache/james/jwt/OidcJwtTokenVerifier.java +++ b/server/protocols/jwt/src/main/java/org/apache/james/jwt/OidcJwtTokenVerifier.java @@ -22,36 +22,73 @@ package org.apache.james.jwt; import java.net.URL; import java.util.Optional; +import org.apache.james.core.Username; import org.apache.james.jwt.introspection.IntrospectionEndpoint; import org.apache.james.jwt.introspection.TokenIntrospectionResponse; import org.reactivestreams.Publisher; +import com.google.common.annotations.VisibleForTesting; import reactor.core.publisher.Mono; public class OidcJwtTokenVerifier { public static final CheckTokenClient CHECK_TOKEN_CLIENT = new DefaultCheckTokenClient(); - public static Optional<String> verifySignatureAndExtractClaim(String jwtToken, URL jwksURL, String claimName) { - return new JwtTokenVerifier(JwksPublicKeyProvider.of(jwksURL)) - .verifyAndExtractClaim(jwtToken, claimName, String.class); + private final OidcSASLConfiguration oidcSASLConfiguration; + + public OidcJwtTokenVerifier(OidcSASLConfiguration oidcSASLConfiguration) { + this.oidcSASLConfiguration = oidcSASLConfiguration; + } + + public Optional<Username> validateToken(String token) { + if (oidcSASLConfiguration.isCheckTokenByIntrospectionEndpoint()) { + return validTokenWithIntrospection(token); + } else if (oidcSASLConfiguration.isCheckTokenByUserinfoEndpoint()) { + return validTokenWithUserInfo(token); + } else { + return verifySignatureAndExtractClaim(token) + .map(Username::of); + } + } + + private Optional<Username> validTokenWithUserInfo(String token) { + return Mono.from(verifyWithUserinfo(token, oidcSASLConfiguration.getUserInfoEndpoint().orElseThrow())) + .blockOptional() + .map(Username::of); + } + + private Optional<Username> validTokenWithIntrospection(String token) { + return Mono.from(verifyWithIntrospection(token, + oidcSASLConfiguration.getIntrospectionEndpoint() + .map(endpoint -> new IntrospectionEndpoint(endpoint, oidcSASLConfiguration.getIntrospectionEndpointAuthorization())) + .orElseThrow())) + .blockOptional() + .map(Username::of); + } + + @VisibleForTesting + Optional<String> verifySignatureAndExtractClaim(String jwtToken) { + return new JwtTokenVerifier(JwksPublicKeyProvider.of(oidcSASLConfiguration.getJwksURL())) + .verifyAndExtractClaim(jwtToken, oidcSASLConfiguration.getClaim(), String.class); } - public static Publisher<String> verifyWithIntrospection(String jwtToken, URL jwksURL, String claimName, IntrospectionEndpoint introspectionEndpoint) { - return Mono.fromCallable(() -> verifySignatureAndExtractClaim(jwtToken, jwksURL, claimName)) + @VisibleForTesting + Publisher<String> verifyWithIntrospection(String jwtToken, IntrospectionEndpoint introspectionEndpoint) { + return Mono.fromCallable(() -> verifySignatureAndExtractClaim(jwtToken)) .flatMap(optional -> optional.map(Mono::just).orElseGet(Mono::empty)) .flatMap(claimResult -> Mono.from(CHECK_TOKEN_CLIENT.introspect(introspectionEndpoint, jwtToken)) .filter(TokenIntrospectionResponse::active) - .filter(tokenIntrospectionResponse -> tokenIntrospectionResponse.claimByPropertyName(claimName) + .filter(tokenIntrospectionResponse -> tokenIntrospectionResponse.claimByPropertyName(oidcSASLConfiguration.getClaim()) .map(claim -> claim.equals(claimResult)) .orElse(false)) .map(activeResponse -> claimResult)); } - public static Publisher<String> verifyWithUserinfo(String jwtToken, URL jwksURL, String claimName, URL userinfoEndpoint) { - return Mono.fromCallable(() -> verifySignatureAndExtractClaim(jwtToken, jwksURL, claimName)) + @VisibleForTesting + Publisher<String> verifyWithUserinfo(String jwtToken, URL userinfoEndpoint) { + return Mono.fromCallable(() -> verifySignatureAndExtractClaim(jwtToken)) .flatMap(optional -> optional.map(Mono::just).orElseGet(Mono::empty)) .flatMap(claimResult -> Mono.from(CHECK_TOKEN_CLIENT.userInfo(userinfoEndpoint, jwtToken)) - .filter(userinfoResponse -> userinfoResponse.claimByPropertyName(claimName) + .filter(userinfoResponse -> userinfoResponse.claimByPropertyName(oidcSASLConfiguration.getClaim()) .map(claim -> claim.equals(claimResult)) .orElse(false)) .map(userinfoResponse -> claimResult)); diff --git a/protocols/api/src/main/java/org/apache/james/protocols/api/OidcSASLConfiguration.java b/server/protocols/jwt/src/main/java/org/apache/james/jwt/OidcSASLConfiguration.java similarity index 57% rename from protocols/api/src/main/java/org/apache/james/protocols/api/OidcSASLConfiguration.java rename to server/protocols/jwt/src/main/java/org/apache/james/jwt/OidcSASLConfiguration.java index 92f0053fd9..c7db3d1e99 100644 --- a/protocols/api/src/main/java/org/apache/james/protocols/api/OidcSASLConfiguration.java +++ b/server/protocols/jwt/src/main/java/org/apache/james/jwt/OidcSASLConfiguration.java @@ -17,7 +17,7 @@ * under the License. * ****************************************************************/ -package org.apache.james.protocols.api; +package org.apache.james.jwt; import java.net.MalformedURLException; import java.net.URI; @@ -27,11 +27,95 @@ import java.util.Optional; import org.apache.commons.configuration2.HierarchicalConfiguration; import org.apache.commons.configuration2.tree.ImmutableNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.github.fge.lambdas.Throwing; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; public class OidcSASLConfiguration { + private static final Logger LOGGER = LoggerFactory.getLogger(OidcSASLConfiguration.class); + + private static final boolean FORCE_INTROSPECT = Boolean.parseBoolean(System.getProperty("james.sasl.oidc.force.introspect", "true")); + + @VisibleForTesting + static Builder builder() { + return new Builder(); + } + + public static class Builder { + private URL jwksURL; + private String claim; + private URL oidcConfigurationURL; + private String scope; + private Optional<URL> introspectionEndpoint = Optional.empty(); + private Optional<String> introspectionEndpointAuthorization = Optional.empty(); + private Optional<URL> userInfoEndpoint = Optional.empty(); + + private Builder() { + } + + public Builder jwksURL(URL jwksURL) { + this.jwksURL = jwksURL; + return this; + } + + public Builder claim(String claim) { + this.claim = claim; + return this; + } + + public Builder oidcConfigurationURL(URL oidcConfigurationURL) { + this.oidcConfigurationURL = oidcConfigurationURL; + return this; + } + + public Builder scope(String scope) { + this.scope = scope; + return this; + } + + public Builder introspectionEndpoint(Optional<URL> introspectionEndpoint) { + this.introspectionEndpoint = introspectionEndpoint; + return this; + } + + public Builder introspectionEndpoint(URL introspectionEndpoint) { + this.introspectionEndpoint = Optional.ofNullable(introspectionEndpoint); + return this; + } + + public Builder introspectionEndpointAuthorization(Optional<String> introspectionEndpointAuthorization) { + this.introspectionEndpointAuthorization = introspectionEndpointAuthorization; + return this; + } + + public Builder introspectionEndpointAuthorization(String introspectionEndpointAuthorization) { + this.introspectionEndpointAuthorization = Optional.ofNullable(introspectionEndpointAuthorization); + return this; + } + + public Builder userInfoEndpoint(Optional<URL> userInfoEndpoint) { + this.userInfoEndpoint = userInfoEndpoint; + return this; + } + + public Builder userInfoEndpoint(URL userInfoEndpoint) { + this.userInfoEndpoint = Optional.ofNullable(userInfoEndpoint); + return this; + } + + public OidcSASLConfiguration build() { + Preconditions.checkNotNull(jwksURL, "jwksURL is mandatory"); + Preconditions.checkNotNull(claim, "claim is mandatory"); + Preconditions.checkNotNull(oidcConfigurationURL, "oidcConfigurationURL is mandatory"); + Preconditions.checkNotNull(scope, "scope is mandatory"); + + return new OidcSASLConfiguration(jwksURL, claim, oidcConfigurationURL, scope, + introspectionEndpoint, introspectionEndpointAuthorization, userInfoEndpoint); + } + } public static OidcSASLConfiguration parse(HierarchicalConfiguration<ImmutableNode> configuration) throws MalformedURLException, URISyntaxException { String jwksURL = configuration.getString("jwksURL", null); @@ -47,6 +131,14 @@ public class OidcSASLConfiguration { String introspectionUrl = configuration.getString("introspection.url", null); String userInfoUrl = configuration.getString("userinfo.url", null); + if (introspectionUrl == null) { + if (FORCE_INTROSPECT) { + throw new IllegalArgumentException("'introspection.url' is mandatory for secure set up. Disable this check with -Djames.sasl.oidc.force.introspect=false."); + } else { + LOGGER.warn("'introspection.url' is mandatory for secure set up. This check was disabled with -Djames.sasl.oidc.force.introspect=false."); + } + } + return new OidcSASLConfiguration(new URI(jwksURL).toURL(), claim, new URI(oidcConfigurationURL).toURL(), scope, Optional.ofNullable(introspectionUrl) .map(Throwing.function(value -> new URI(value).toURL())), Optional.ofNullable(configuration.getString("introspection.auth", null)), Optional.ofNullable(userInfoUrl).map(Throwing.function(value -> new URI(value).toURL()))); @@ -60,7 +152,7 @@ public class OidcSASLConfiguration { private final Optional<String> introspectionEndpointAuthorization; private final Optional<URL> userInfoEndpoint; - public OidcSASLConfiguration(URL jwksURL, + private OidcSASLConfiguration(URL jwksURL, String claim, URL oidcConfigurationURL, String scope, diff --git a/server/protocols/jwt/src/test/java/org/apache/james/jwt/OidcJwtTokenVerifierTest.java b/server/protocols/jwt/src/test/java/org/apache/james/jwt/OidcJwtTokenVerifierTest.java index 0c9c1f597a..8fe910dfba 100644 --- a/server/protocols/jwt/src/test/java/org/apache/james/jwt/OidcJwtTokenVerifierTest.java +++ b/server/protocols/jwt/src/test/java/org/apache/james/jwt/OidcJwtTokenVerifierTest.java @@ -80,7 +80,7 @@ class OidcJwtTokenVerifierTest { @Test void verifyAndClaimShouldReturnClaimValueWhenValidTokenHasKid() { - Optional<String> emailAddress = OidcJwtTokenVerifier.verifySignatureAndExtractClaim(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "email_address"); + Optional<String> emailAddress = new OidcJwtTokenVerifier(configForClaim("email_address")).verifySignatureAndExtractClaim(OidcTokenFixture.VALID_TOKEN); SoftAssertions.assertSoftly(softly -> { softly.assertThat(emailAddress.isPresent()).isTrue(); softly.assertThat(emailAddress.get()).isEqualTo("[email protected]"); @@ -89,7 +89,7 @@ class OidcJwtTokenVerifierTest { @Test void verifyAndClaimShouldReturnClaimValueWhenValidTokenHasNotKid() { - Optional<String> emailAddress = OidcJwtTokenVerifier.verifySignatureAndExtractClaim(OidcTokenFixture.VALID_TOKEN_HAS_NOT_KID, getJwksURL(), "email_address"); + Optional<String> emailAddress = new OidcJwtTokenVerifier(configForClaim("email_address")).verifySignatureAndExtractClaim(OidcTokenFixture.VALID_TOKEN_HAS_NOT_KID); SoftAssertions.assertSoftly(softly -> { softly.assertThat(emailAddress.isPresent()).isTrue(); softly.assertThat(emailAddress.get()).isEqualTo("[email protected]"); @@ -110,7 +110,7 @@ class OidcJwtTokenVerifierTest { .signWith(toPrivateKey(OidcTokenFixture.PRIVATE_KEY_BASE64), Jwts.SIG.RS256) .compact(); - assertThatThrownBy(() -> OidcJwtTokenVerifier.verifySignatureAndExtractClaim(jws, getJwksURL(), "kid")) + assertThatThrownBy(() -> new OidcJwtTokenVerifier(configForClaim("kid")).verifySignatureAndExtractClaim(jws)) .isInstanceOf(RuntimeException.class) .hasMessageContaining("Rejecting a ZIP JWT"); } @@ -126,7 +126,7 @@ class OidcJwtTokenVerifierTest { boolean prev = JwtTokenVerifier.allowZipJWT; JwtTokenVerifier.allowZipJWT = true; try { - assertThatCode(() -> OidcJwtTokenVerifier.verifySignatureAndExtractClaim(jws, getJwksURL(), "kid")) + assertThatCode(() -> new OidcJwtTokenVerifier(configForClaim("kid")).verifySignatureAndExtractClaim(jws)) .doesNotThrowAnyException(); } finally { JwtTokenVerifier.allowZipJWT = prev; @@ -135,19 +135,22 @@ class OidcJwtTokenVerifierTest { @Test void verifyAndClaimShouldReturnEmptyWhenValidTokenHasNotFoundKid() { - assertThat(OidcJwtTokenVerifier.verifySignatureAndExtractClaim(OidcTokenFixture.VALID_TOKEN_HAS_NOT_FOUND_KID, getJwksURL(), "email_address")) + assertThat(new OidcJwtTokenVerifier(configForClaim("email_address")) + .verifySignatureAndExtractClaim(OidcTokenFixture.VALID_TOKEN_HAS_NOT_FOUND_KID)) .isEmpty(); } @Test void verifyAndClaimShouldReturnEmptyWhenClaimNameNotFound() { - assertThat(OidcJwtTokenVerifier.verifySignatureAndExtractClaim(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "not_found")) + assertThat(new OidcJwtTokenVerifier(configForClaim("not_found")) + .verifySignatureAndExtractClaim(OidcTokenFixture.VALID_TOKEN)) .isEmpty(); } @Test void verifyAndClaimShouldReturnEmptyWhenInvalidToken() { - assertThat(OidcJwtTokenVerifier.verifySignatureAndExtractClaim(OidcTokenFixture.INVALID_TOKEN, getJwksURL(), "email_address")) + assertThat(new OidcJwtTokenVerifier(configForClaim("email_address")) + .verifySignatureAndExtractClaim(OidcTokenFixture.INVALID_TOKEN)) .isEmpty(); } @@ -157,7 +160,8 @@ class OidcJwtTokenVerifierTest { .when(HttpRequest.request().withPath(USERINFO_PATH)) .respond(HttpResponse.response().withStatusCode(201)); - assertThatThrownBy(() -> Mono.from(OidcJwtTokenVerifier.verifyWithUserinfo(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "email_address", getUserInfoEndpoint())) + assertThatThrownBy(() -> Mono.from(new OidcJwtTokenVerifier(configForClaim("email_address")) + .verifyWithUserinfo(OidcTokenFixture.VALID_TOKEN, getUserInfoEndpoint())) .block()) .isInstanceOf(UserInfoCheckException.class) .hasMessageContaining("Error when check token by userInfo"); @@ -171,7 +175,8 @@ class OidcJwtTokenVerifierTest { .withHeader("Content-Type", "application/json") .withBody("badResponse1", StandardCharsets.UTF_8)); - assertThatThrownBy(() -> Mono.from(OidcJwtTokenVerifier.verifyWithUserinfo(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "email_address", getUserInfoEndpoint())) + assertThatThrownBy(() -> Mono.from(new OidcJwtTokenVerifier(configForClaim("email_address")) + .verifyWithUserinfo(OidcTokenFixture.VALID_TOKEN, getUserInfoEndpoint())) .block()) .isInstanceOf(UserInfoCheckException.class) .hasMessageContaining("Error when check token by userInfo"); @@ -192,11 +197,25 @@ class OidcJwtTokenVerifierTest { .withHeader("Content-Type", "application/json") .withBody(userInfoResponse, StandardCharsets.UTF_8)); - assertThat(Mono.from(OidcJwtTokenVerifier.verifyWithUserinfo(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "preferred_username", getUserInfoEndpoint())) + assertThat(Mono.from(new OidcJwtTokenVerifier(configForClaim("preferred_username")) + .verifyWithUserinfo(OidcTokenFixture.VALID_TOKEN, getUserInfoEndpoint())) .block()) .isNull(); } + private OidcSASLConfiguration configForClaim(String claim) { + try { + return OidcSASLConfiguration.builder() + .jwksURL(getJwksURL()) + .scope("email") + .oidcConfigurationURL(new URL("https://whatever.nte")) + .claim(claim) + .build(); + } catch (MalformedURLException e) { + throw new RuntimeException(e); + } + } + @Test void verifyWithUserinfoShouldReturnClaimValueWhenPassCheckToken() { mockServer @@ -205,7 +224,8 @@ class OidcJwtTokenVerifierTest { .withHeader("Content-Type", "application/json") .withBody(USERINFO_RESPONSE, StandardCharsets.UTF_8)); - assertThat(Mono.from(OidcJwtTokenVerifier.verifyWithUserinfo(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "email_address", getUserInfoEndpoint())) + assertThat(Mono.from(new OidcJwtTokenVerifier(configForClaim("email_address")) + .verifyWithUserinfo(OidcTokenFixture.VALID_TOKEN, getUserInfoEndpoint())) .block()) .isEqualTo("[email protected]"); } @@ -218,7 +238,8 @@ class OidcJwtTokenVerifierTest { .withHeader("Content-Type", "application/json") .withBody(USERINFO_RESPONSE, StandardCharsets.UTF_8)); - assertThat(Mono.from(OidcJwtTokenVerifier.verifyWithUserinfo(OidcTokenFixture.INVALID_TOKEN, getJwksURL(), "email_address", getUserInfoEndpoint())) + assertThat(Mono.from(new OidcJwtTokenVerifier(configForClaim("email_address")) + .verifyWithUserinfo(OidcTokenFixture.INVALID_TOKEN, getUserInfoEndpoint())) .block()) .isNull(); } @@ -239,7 +260,7 @@ class OidcJwtTokenVerifierTest { .withHeader("Content-Type", "application/json") .withBody(userInfoResponse, StandardCharsets.UTF_8)); - assertThat(Mono.from(OidcJwtTokenVerifier.verifyWithUserinfo(OidcTokenFixture.INVALID_TOKEN, getJwksURL(), "preferred_username", getUserInfoEndpoint())) + assertThat(Mono.from(new OidcJwtTokenVerifier(configForClaim("preferred_username")).verifyWithUserinfo(OidcTokenFixture.INVALID_TOKEN, getUserInfoEndpoint())) .block()) .isNull(); } @@ -250,8 +271,8 @@ class OidcJwtTokenVerifierTest { .when(HttpRequest.request().withPath(INTROSPECTION_PATH)) .respond(HttpResponse.response().withStatusCode(201)); - assertThatThrownBy(() -> Mono.from(OidcJwtTokenVerifier.verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "email_address", - new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) + assertThatThrownBy(() -> Mono.from(new OidcJwtTokenVerifier(configForClaim("email_address")) + .verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) .block()) .isInstanceOf(TokenIntrospectionException.class) .hasMessageContaining("Error when introspecting token"); @@ -265,8 +286,8 @@ class OidcJwtTokenVerifierTest { .withHeader("Content-Type", "application/json") .withBody("badResponse1", StandardCharsets.UTF_8)); - assertThatThrownBy(() -> Mono.from(OidcJwtTokenVerifier.verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "email_address", - new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) + assertThatThrownBy(() -> Mono.from(new OidcJwtTokenVerifier(configForClaim("email_address")) + .verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) .block()) .isInstanceOf(TokenIntrospectionException.class) .hasMessageContaining("Error when introspecting token"); @@ -295,8 +316,8 @@ class OidcJwtTokenVerifierTest { .withHeader("Content-Type", "application/json") .withBody(introspectionResponse, StandardCharsets.UTF_8)); - assertThatThrownBy(() -> Mono.from(OidcJwtTokenVerifier.verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "email_address", - new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) + assertThatThrownBy(() -> Mono.from(new OidcJwtTokenVerifier(configForClaim("email_address")) + .verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) .block()) .isInstanceOf(TokenIntrospectionException.class) .hasMessageContaining("Error when introspecting token"); @@ -326,8 +347,8 @@ class OidcJwtTokenVerifierTest { .withHeader("Content-Type", "application/json") .withBody(introspectionResponse, StandardCharsets.UTF_8)); - assertThatThrownBy(() -> Mono.from(OidcJwtTokenVerifier.verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "email_address", - new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) + assertThatThrownBy(() -> Mono.from(new OidcJwtTokenVerifier(configForClaim("email_address")) + .verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) .block()) .isInstanceOf(TokenIntrospectionException.class) .hasMessageContaining("Error when introspecting token"); @@ -341,8 +362,8 @@ class OidcJwtTokenVerifierTest { .withHeader("Content-Type", "application/json") .withBody(INTROSPECTION_RESPONSE, StandardCharsets.UTF_8)); - assertThat(Mono.from(OidcJwtTokenVerifier.verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "email_address", - new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) + assertThat(Mono.from(new OidcJwtTokenVerifier(configForClaim("email_address")) + .verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) .block()) .isEqualTo("[email protected]"); } @@ -363,8 +384,8 @@ class OidcJwtTokenVerifierTest { .withHeader("Content-Type", "application/json") .withBody(introspectionResponse, StandardCharsets.UTF_8)); - assertThat(Mono.from(OidcJwtTokenVerifier.verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "preferred_username", - new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) + assertThat(Mono.from(new OidcJwtTokenVerifier(configForClaim("preferred_username")) + .verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) .block()) .isNull(); } @@ -385,8 +406,8 @@ class OidcJwtTokenVerifierTest { .withHeader("Content-Type", "application/json") .withBody(introspectionResponse, StandardCharsets.UTF_8)); - assertThat(Mono.from(OidcJwtTokenVerifier.verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, getJwksURL(), "preferred_username", - new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) + assertThat(Mono.from(new OidcJwtTokenVerifier(configForClaim("preferred_username")) + .verifyWithIntrospection(OidcTokenFixture.VALID_TOKEN, new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) .block()) .isNull(); } @@ -399,8 +420,8 @@ class OidcJwtTokenVerifierTest { .withHeader("Content-Type", "application/json") .withBody(INTROSPECTION_RESPONSE, StandardCharsets.UTF_8)); - assertThat(Mono.from(OidcJwtTokenVerifier.verifyWithIntrospection(OidcTokenFixture.INVALID_TOKEN, getJwksURL(), "email_address", - new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) + assertThat(Mono.from(new OidcJwtTokenVerifier(configForClaim("email_address")) + .verifyWithIntrospection(OidcTokenFixture.INVALID_TOKEN, new IntrospectionEndpoint(getIntrospectionEndpoint(), Optional.empty()))) .block()) .isNull(); } diff --git a/server/protocols/protocols-imap4/pom.xml b/server/protocols/protocols-imap4/pom.xml index 473752bf93..45e27242cc 100644 --- a/server/protocols/protocols-imap4/pom.xml +++ b/server/protocols/protocols-imap4/pom.xml @@ -188,7 +188,7 @@ </systemPropertyVariables> <argLine>-Djava.library.path= -javaagent:"${settings.localRepository}"/org/jacoco/org.jacoco.agent/${jacoco-maven-plugin.version}/org.jacoco.agent-${jacoco-maven-plugin.version}-runtime.jar=destfile=${basedir}/target/jacoco.exec - -Xms1024m -Xmx2048m</argLine> + -Xms1024m -Xmx2048m -Djames.sasl.oidc.force.introspect=false</argLine> <reuseForks>true</reuseForks> <!-- Fail tests longer than 30 minutes, prevent form random locking tests --> <forkedProcessTimeoutInSeconds>1800</forkedProcessTimeoutInSeconds> diff --git a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java index b66129f04c..e0295b4e09 100644 --- a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java +++ b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/IMAPServer.java @@ -50,10 +50,10 @@ import org.apache.james.imap.api.process.ImapSession; import org.apache.james.imap.api.process.SelectedMailbox; import org.apache.james.imap.decode.ImapDecoder; import org.apache.james.imap.encode.ImapEncoder; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.mailbox.MailboxSession; import org.apache.james.mailbox.model.MailboxId; import org.apache.james.metrics.api.GaugeRegistry; -import org.apache.james.protocols.api.OidcSASLConfiguration; import org.apache.james.protocols.lib.netty.AbstractConfigurableAsyncServer; import org.apache.james.protocols.netty.AbstractChannelPipelineFactory; import org.apache.james.protocols.netty.ChannelHandlerFactory; diff --git a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/NettyImapSession.java b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/NettyImapSession.java index 7ec85cdcab..32f663d6d3 100644 --- a/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/NettyImapSession.java +++ b/server/protocols/protocols-imap4/src/main/java/org/apache/james/imapserver/netty/NettyImapSession.java @@ -39,8 +39,8 @@ import org.apache.james.imap.api.process.ImapSession; import org.apache.james.imap.api.process.SelectedMailbox; import org.apache.james.imap.encode.ImapResponseWriter; import org.apache.james.imap.message.Literal; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.mailbox.MailboxSession; -import org.apache.james.protocols.api.OidcSASLConfiguration; import org.apache.james.protocols.netty.Encryption; import org.apache.james.protocols.netty.LineHandlerAware; import org.apache.james.util.MDCBuilder; diff --git a/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/netty/LMTPServer.java b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/netty/LMTPServer.java index 9eb8f12264..f367ea7b9d 100644 --- a/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/netty/LMTPServer.java +++ b/server/protocols/protocols-lmtp/src/main/java/org/apache/james/lmtpserver/netty/LMTPServer.java @@ -23,9 +23,9 @@ import java.util.Optional; import org.apache.commons.configuration2.HierarchicalConfiguration; import org.apache.commons.configuration2.ex.ConfigurationException; import org.apache.commons.configuration2.tree.ImmutableNode; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.lmtpserver.CoreCmdHandlerLoader; import org.apache.james.lmtpserver.jmx.JMXHandlersLoader; -import org.apache.james.protocols.api.OidcSASLConfiguration; import org.apache.james.protocols.api.ProtocolSession; import org.apache.james.protocols.api.ProtocolTransport; import org.apache.james.protocols.lib.handler.HandlersPackage; diff --git a/server/protocols/protocols-smtp/pom.xml b/server/protocols/protocols-smtp/pom.xml index f96f78a01d..eae01359bd 100644 --- a/server/protocols/protocols-smtp/pom.xml +++ b/server/protocols/protocols-smtp/pom.xml @@ -226,7 +226,7 @@ </systemPropertyVariables> <argLine>-Djava.library.path= -javaagent:"${settings.localRepository}"/org/jacoco/org.jacoco.agent/${jacoco-maven-plugin.version}/org.jacoco.agent-${jacoco-maven-plugin.version}-runtime.jar=destfile=${basedir}/target/jacoco.exec - -Xms512m -Xmx1024m</argLine> + -Xms512m -Xmx1024m -Djames.sasl.oidc.force.introspect=false</argLine> <reuseForks>true</reuseForks> <!-- Fail tests longer than 30 minutes, prevent form random locking tests --> <forkedProcessTimeoutInSeconds>1800</forkedProcessTimeoutInSeconds> diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/ConfigurationAuthHook.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/ConfigurationAuthHook.java index 735ff574ff..f68527afc1 100644 --- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/ConfigurationAuthHook.java +++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/ConfigurationAuthHook.java @@ -29,7 +29,7 @@ import org.apache.commons.configuration2.ex.ConfigurationException; import org.apache.commons.configuration2.tree.ImmutableNode; import org.apache.commons.lang3.NotImplementedException; import org.apache.james.core.Username; -import org.apache.james.protocols.api.OidcSASLConfiguration; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.protocols.smtp.SMTPSession; import org.apache.james.protocols.smtp.hook.AuthHook; import org.apache.james.protocols.smtp.hook.HookResult; diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/UsersRepositoryAuthHook.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/UsersRepositoryAuthHook.java index 91eda43e86..d60b0dafcc 100644 --- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/UsersRepositoryAuthHook.java +++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/UsersRepositoryAuthHook.java @@ -24,11 +24,10 @@ import jakarta.inject.Inject; import org.apache.james.core.Username; import org.apache.james.jwt.OidcJwtTokenVerifier; -import org.apache.james.jwt.introspection.IntrospectionEndpoint; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.mailbox.Authorizator; import org.apache.james.mailbox.exception.MailboxException; import org.apache.james.protocols.api.OIDCSASLParser; -import org.apache.james.protocols.api.OidcSASLConfiguration; import org.apache.james.protocols.smtp.SMTPSession; import org.apache.james.protocols.smtp.hook.AuthHook; import org.apache.james.protocols.smtp.hook.HookResult; @@ -38,8 +37,6 @@ import org.apache.james.user.api.UsersRepositoryException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import reactor.core.publisher.Mono; - /** * This Auth hook can be used to authenticate against the james user repository */ @@ -77,7 +74,7 @@ public class UsersRepositoryAuthHook implements AuthHook { @Override public HookResult doSasl(SMTPSession session, OidcSASLConfiguration configuration, String initialResponse) { return OIDCSASLParser.parse(initialResponse) - .flatMap(oidcInitialResponseValue -> validateToken(configuration, oidcInitialResponseValue.getToken()) + .flatMap(oidcInitialResponseValue -> new OidcJwtTokenVerifier(configuration).validateToken(oidcInitialResponseValue.getToken()) .map(authenticatedUser -> { Username associatedUser = Username.of(oidcInitialResponseValue.getAssociatedUser()); if (!associatedUser.equals(authenticatedUser)) { @@ -115,35 +112,4 @@ public class UsersRepositoryAuthHook implements AuthHook { return HookResult.DECLINED; } } - - private Optional<Username> validateToken(OidcSASLConfiguration oidcSASLConfiguration, String token) { - if (oidcSASLConfiguration.isCheckTokenByIntrospectionEndpoint()) { - return validTokenWithIntrospection(oidcSASLConfiguration, token); - } else if (oidcSASLConfiguration.isCheckTokenByUserinfoEndpoint()) { - return validTokenWithUserInfo(oidcSASLConfiguration, token); - } else { - return OidcJwtTokenVerifier.verifySignatureAndExtractClaim(token, oidcSASLConfiguration.getJwksURL(), oidcSASLConfiguration.getClaim()) - .map(Username::of); - } - } - - private Optional<Username> validTokenWithUserInfo(OidcSASLConfiguration oidcSASLConfiguration, String token) { - return Mono.from(OidcJwtTokenVerifier.verifyWithUserinfo(token, - oidcSASLConfiguration.getJwksURL(), - oidcSASLConfiguration.getClaim(), - oidcSASLConfiguration.getUserInfoEndpoint().orElseThrow())) - .blockOptional() - .map(Username::of); - } - - private static Optional<Username> validTokenWithIntrospection(OidcSASLConfiguration oidcSASLConfiguration, String token) { - return Mono.from(OidcJwtTokenVerifier.verifyWithIntrospection(token, - oidcSASLConfiguration.getJwksURL(), - oidcSASLConfiguration.getClaim(), - oidcSASLConfiguration.getIntrospectionEndpoint() - .map(endpoint -> new IntrospectionEndpoint(endpoint, oidcSASLConfiguration.getIntrospectionEndpointAuthorization())) - .orElseThrow())) - .blockOptional() - .map(Username::of); - } } diff --git a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/netty/SMTPServer.java b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/netty/SMTPServer.java index 5229643bcb..5b2d0e3987 100644 --- a/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/netty/SMTPServer.java +++ b/server/protocols/protocols-smtp/src/main/java/org/apache/james/smtpserver/netty/SMTPServer.java @@ -44,7 +44,7 @@ import org.apache.james.core.Disconnector; import org.apache.james.core.Username; import org.apache.james.dnsservice.api.DNSService; import org.apache.james.dnsservice.library.netmatcher.NetMatcher; -import org.apache.james.protocols.api.OidcSASLConfiguration; +import org.apache.james.jwt.OidcSASLConfiguration; import org.apache.james.protocols.api.ProtocolSession; import org.apache.james.protocols.api.ProtocolTransport; import org.apache.james.protocols.lib.handler.HandlersPackage; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
