content: /*
   * 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.kafka.common.security.scram.internals;
  
  import org.apache.kafka.common.security.authenticator.CredentialCache;
  import org.apache.kafka.common.security.scram.ScramCredential;
  
  import org.junit.jupiter.api.BeforeEach;
  import org.junit.jupiter.api.Test;
  
  import java.security.NoSuchAlgorithmException;
  import java.util.Arrays;
  
  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
  import static org.junit.jupiter.api.Assertions.assertEquals;
  import static org.junit.jupiter.api.Assertions.assertNotEquals;
  import static org.junit.jupiter.api.Assertions.assertNotNull;
  import static org.junit.jupiter.api.Assertions.assertNull;
  import static org.junit.jupiter.api.Assertions.assertThrows;
  import static org.junit.jupiter.api.Assertions.assertTrue;
  
  
  public class ScramCredentialUtilsTest {
  
      private ScramFormatter formatter;
  
      @BeforeEach
      public void setUp() throws NoSuchAlgorithmException {
          formatter = new ScramFormatter(ScramMechanism.SCRAM_SHA_256);
      }
  
      @Test
      public void stringConversion() {
          ScramCredential credential = formatter.generateCredential("password", 1024);
          assertTrue(credential.salt().length > 0, "Salt must not be empty");
          assertTrue(credential.storedKey().length > 0, "Stored key must not be empty");
          assertTrue(credential.serverKey().length > 0, "Server key must not be empty");
          ScramCredential credential2 = ScramCredentialUtils.credentialFromString(ScramCredentialUtils.credentialToString(credential));
          assertArrayEquals(credential.salt(), credential2.salt());
          assertArrayEquals(credential.storedKey(), credential2.storedKey());
          assertArrayEquals(credential.serverKey(), credential2.serverKey());
          assertEquals(credential.iterations(), credential2.iterations());
      }
  
      @Test
      public void generateCredential() {
          ScramCredential credential1 = formatter.generateCredential("password", 4096);
          ScramCredential credential2 = formatter.generateCredential("password", 4096);
          // Random salt should ensure that the credentials persisted are different every time
          assertNotEquals(ScramCredentialUtils.credentialToString(credential1), ScramCredentialUtils.credentialToString(credential2));
      }
  
      @Test
      public void invalidCredential() {
          assertThrows(IllegalArgumentException.class, () -> ScramCredentialUtils.credentialFromString("abc"));
      }
  
      @Test
      public void missingFields() {
          String cred = ScramCredentialUtils.credentialToString(formatter.generateCredential("password", 2048));
          assertThrows(IllegalArgumentException.class, () -> ScramCredentialUtils.credentialFromString(cred.substring(cred.indexOf(','))));
      }
  
      @Test
      public void extraneousFields() {
          String cred = ScramCredentialUtils.credentialToString(formatter.generateCredential("password", 2048));
          assertThrows(IllegalArgumentException.class, () -> ScramCredentialUtils.credentialFromString(cred + ",a=test"));
      }
  
      @Test
      public void scramCredentialCache() throws Exception {
          CredentialCache cache = new CredentialCache();
          ScramCredentialUtils.createCache(cache, Arrays.asList("SCRAM-SHA-512", "PLAIN"));
          assertNotNull(cache.cache(ScramMechanism.SCRAM_SHA_512.mechanismName(), ScramCredential.class), "Cache not created for enabled mechanism");
          assertNull(cache.cache(ScramMechanism.SCRAM_SHA_256.mechanismName(), ScramCredential.class), "Cache created for disabled mechanism");
  
          CredentialCache.Cache<ScramCredential> sha512Cache = cache.cache(ScramMechanism.SCRAM_SHA_512.mechanismName(), ScramCredential.class);
          ScramFormatter formatter = new ScramFormatter(ScramMechanism.SCRAM_SHA_512);
          ScramCredential credentialA = formatter.generateCredential("password", 4096);
          sha512Cache.put("userA", credentialA);
          assertEquals(credentialA, sha512Cache.get("userA"));
          assertNull(sha512Cache.get("userB"), "Invalid user credential");
      }
  }
  