chibenwa commented on code in PR #3059: URL: https://github.com/apache/james-project/pull/3059#discussion_r3363926311
########## protocols/api/src/test/java/org/apache/james/protocols/api/sasl/SaslMechanismContractTest.java: ########## @@ -0,0 +1,371 @@ +/**************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one * + * or more contributor license agreements. See the NOTICE file * + * distributed with this work for additional information * + * regarding copyright ownership. The ASF licenses this file * + * to you 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 org.apache.james.protocols.api.sasl; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import org.apache.james.core.Username; +import org.junit.jupiter.api.Test; + +/** + * Validates the shared SASL SPI shape with fake mechanisms before wiring real protocol mechanisms to it. + */ +class SaslMechanismContractTest { + private static final Username AUTHENTICATION_ID = Username.of("[email protected]"); + private static final Username AUTHORIZATION_ID = Username.of("[email protected]"); + private static final SaslIdentity SAME_USER_IDENTITY = new SaslIdentity(AUTHENTICATION_ID, AUTHENTICATION_ID); + private static final SaslIdentity DELEGATED_IDENTITY = new SaslIdentity(AUTHENTICATION_ID, AUTHORIZATION_ID); + + /** + * Models one-step mechanisms that can immediately succeed or fail on the first server step. + */ + private static class FixedStepMechanism implements SaslMechanism { + private final SaslStep firstStep; + + private FixedStepMechanism(SaslStep firstStep) { + this.firstStep = firstStep; + } + + @Override + public String name() { + return "FIXED"; + } + + @Override + public boolean supports(SaslProtocol protocol) { + return protocol == SaslProtocol.IMAP; + } + + @Override + public boolean isAvailable(SaslSessionContext context) { + return true; + } + + @Override + public SaslExchange start(SaslInitialRequest request, SaslSessionContext context) { + return new FixedStepExchange(firstStep); + } + } + + private static class FixedStepExchange implements SaslExchange { + private final SaslStep firstStep; + private boolean aborted; + private boolean closed; + + private FixedStepExchange(SaslStep firstStep) { + this.firstStep = firstStep; + } + + @Override + public SaslStep firstStep() { + return firstStep; + } + + @Override + public SaslStep onResponse(byte[] clientResponse) { + return firstStep; + } + + @Override + public void abort() { + aborted = true; + } + + @Override + public void close() { + closed = true; + } + } + + /** + * Models challenge/response mechanisms where state must survive between client lines. + */ + private static class TwoStepMechanism implements SaslMechanism { + @Override + public String name() { + return "TWO_STEP"; + } + + @Override + public boolean supports(SaslProtocol protocol) { + return protocol == SaslProtocol.IMAP; + } + + @Override + public boolean isAvailable(SaslSessionContext context) { + return true; + } + + @Override + public SaslExchange start(SaslInitialRequest request, SaslSessionContext context) { + return new TwoStepExchange(); + } + } + + private static class TwoStepExchange implements SaslExchange { + private boolean challenged; + + @Override + public SaslStep firstStep() { + challenged = true; + return new SaslStep.Challenge(Optional.of(bytes("continue"))); + } + + @Override + public SaslStep onResponse(byte[] clientResponse) { + if (!challenged) { + return new SaslStep.Failure("response received before challenge"); + } + if (new String(clientResponse, StandardCharsets.UTF_8).equals("accepted")) { + return new SaslStep.Success(SAME_USER_IDENTITY, Optional.empty()); + } + return new SaslStep.Failure("rejected"); + } + + @Override + public void abort() { + } + + @Override + public void close() { + } + } + + /** + * Models generic password mechanisms that parse SASL payloads but delegate credential verification to the protocol. + */ + private static class PasswordLikeMechanism implements SaslMechanism { + @Override + public String name() { + return "PASSWORD_LIKE"; + } + + @Override + public boolean supports(SaslProtocol protocol) { + return protocol == SaslProtocol.IMAP; + } + + @Override + public boolean isAvailable(SaslSessionContext context) { + return context.service(PasswordSaslAuthenticationService.class).isPresent(); + } Review Comment: If I do not want password why wouldn't I simply remove the associated sasl mechanism ? -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected] --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
