/*
 * The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
 * (the "License"). You may not use this work except in compliance with the License, which is
 * available at www.apache.org/licenses/LICENSE-2.0
 *
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied, as more fully set forth in the License.
 *
 * See the NOTICE file distributed with this work for information regarding copyright ownership.
 */

package alluxio.security.authentication;

import alluxio.Configuration;
import alluxio.ConfigurationTestUtils;
import alluxio.PropertyKey;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.sasl.AuthenticationException;
import javax.security.sasl.AuthorizeCallback;

/**
 * Tests the {@link PlainSaslServerCallbackHandler} class.
 */
public final class PlainSaslServerCallbackHandlerTest {
  private CallbackHandler mPlainServerCBHandler;

  /**
   * The exception expected to be thrown.
   */
  @Rule
  public ExpectedException mThrown = ExpectedException.none();

  /**
   * Sets up the configuration and callback handler before running a test.
   */
  @Before
  public void before() throws Exception {
    Configuration.set(PropertyKey.SECURITY_AUTHENTICATION_CUSTOM_PROVIDER_CLASS,
        NameMatchAuthenticationProvider.class.getName());
    mPlainServerCBHandler = new PlainSaslServerCallbackHandler(
        AuthenticationProvider.Factory.create(AuthType.CUSTOM),
        new Runnable() {
          @Override
          public void run() {}
        });
  }

  @After
  public void after() {
    AuthenticatedClientUser.remove();
    ConfigurationTestUtils.resetConfiguration();
  }

  /**
   * Tests that the authentication callbacks matches.
   */
  @Test
  public void authenticateNameMatch() throws Exception {
    String authenticateId = "alluxio-1";
    NameCallback ncb = new NameCallback(" authentication id: ");
    ncb.setName(authenticateId);

    PasswordCallback pcb = new PasswordCallback(" password: ", false);
    pcb.setPassword("password".toCharArray());

    Callback[] callbacks = new Callback[]{ncb, pcb,
        new AuthorizeCallback(authenticateId, authenticateId)};
    mPlainServerCBHandler.handle(callbacks);
  }

  /**
   * Tests that the authentication callbacks do not match.
   */
  @Test
  public void authenticateNameNotMatch() throws Exception {
    mThrown.expect(AuthenticationException.class);
    mThrown.expectMessage("Only allow the user starting with alluxio");

    String authenticateId = "not-alluxio-1";
    NameCallback ncb = new NameCallback(" authentication id: ");
    ncb.setName(authenticateId);

    PasswordCallback pcb = new PasswordCallback(" password: ", false);
    pcb.setPassword("password".toCharArray());

    Callback[] callbacks = new Callback[]{ncb, pcb,
        new AuthorizeCallback(authenticateId, authenticateId)};
    mPlainServerCBHandler.handle(callbacks);
  }

  /**
   * Tests that the incorrect password should fail the authentication.
   */
  @Test
  public void authenticateCorrectPassword() throws Exception {
    mThrown.expect(AuthenticationException.class);
    mThrown.expectMessage("Wrong password");

    String authenticateId = "alluxio-1";
    NameCallback ncb = new NameCallback(" authentication id: ");
    ncb.setName(authenticateId);

    PasswordCallback pcb = new PasswordCallback(" password: ", false);
    pcb.setPassword("not-password".toCharArray());

    Callback[] callbacks = new Callback[]{ncb, pcb,
        new AuthorizeCallback(authenticateId, authenticateId)};
    mPlainServerCBHandler.handle(callbacks);
  }

  /**
   * An {@link AuthenticationProvider} that only allows users starting with alluxio, password
   * should be "password".
   */
  public static class NameMatchAuthenticationProvider implements AuthenticationProvider {
    @Override
    public void authenticate(String user, String password) throws AuthenticationException {
      if (!user.matches("^alluxio.*")) {
        throw new AuthenticationException("Only allow the user starting with alluxio");
      }
      if (!password.matches("^password")) {
        throw new AuthenticationException("Wrong password");
      }
    }
  }
}

@@ -573,24 +573,28 @@
 onfiguration
+Rule
 ;%0Aimport all
@@ -1396,148 +1396,71 @@
 %0A%0A  
-/**%0A   * Sets up the configuration and callback handler before running a test.%0A   */%0A  @Before%0A  public void before() throws Exception %7B%0A   
+@Rule%0A  public ConfigurationRule mConfigurationRule =%0A      new
  Con
@@ -1469,20 +1469,20 @@
 guration
-.set
+Rule
 (Propert
@@ -1537,24 +1537,26 @@
 SS,%0A        
+  
 NameMatchAut
@@ -1592,16 +1592,156 @@
 Name());
+%0A%0A  /**%0A   * Sets up the configuration and callback handler before running a test.%0A   */%0A  @Before%0A  public void before() throws Exception %7B
 %0A    mPl
@@ -1860,24 +1860,16 @@
 CUSTOM),
-%0A       
  new Run
@@ -2479,32 +2479,40 @@
 ck%5B%5D callbacks =
+%0A       
  new Callback%5B%5D%7B
@@ -2502,32 +2502,33 @@
   new Callback%5B%5D
+ 
 %7Bncb, pcb,%0A     
@@ -2517,32 +2517,24 @@
 %5D %7Bncb, pcb,
-%0A       
  new Authori
@@ -3172,32 +3172,40 @@
 ck%5B%5D callbacks =
+%0A       
  new Callback%5B%5D%7B
@@ -3195,32 +3195,33 @@
   new Callback%5B%5D
+ 
 %7Bncb, pcb,%0A     
@@ -3210,32 +3210,24 @@
 %5D %7Bncb, pcb,
-%0A       
  new Authori
@@ -3861,16 +3861,24 @@
 lbacks =
+%0A       
  new Cal
@@ -3884,16 +3884,17 @@
 llback%5B%5D
+ 
 %7Bncb, pc
@@ -3895,24 +3895,16 @@
 cb, pcb,
-%0A       
  new Aut
@@ -4105,20 +4105,20 @@
 word
-%0A   *
  should
+%0A   *
  be 

Refactor configuration usage in PlainSaslServerCallbackHandlerTest