/*
* 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 org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import java.io.IOException;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.AuthorizeCallback;
import javax.security.sasl.SaslException;
/**
* Tests the {@link PlainSaslServer} class.
*/
public final class PlainSaslServerTest {
private static byte sSEPARATOR = 0x00; // US-ASCII <NUL>
private PlainSaslServer mPlainSaslServer = null;
/**
* The exception expected to be thrown.
*/
@Rule
public ExpectedException mThrown = ExpectedException.none();
/**
* Sets up the server before a test runs.
*/
@Before
public void before() throws Exception {
mPlainSaslServer = new PlainSaslServer(new MockCallbackHandler());
}
/**
* Simulate the authentication data included user information from client side.
*
* @param user The name of the user will be transferred from client side
* @param password The password will be transferred from client side
* @return The response is simulated from the client side
*/
private byte[] getUserInfo(String user, String password) throws Exception {
byte[] auth = user.getBytes("UTF8");
byte[] pw = password.getBytes("UTF8");
byte[] result = new byte[pw.length + auth.length + 2];
int pos = 0;
result[pos++] = sSEPARATOR;
System.arraycopy(auth, 0, result, pos, auth.length);
pos += auth.length;
result[pos++] = sSEPARATOR;
System.arraycopy(pw, 0, result, pos, pw.length);
return result;
}
/**
* Tests the {@link PlainSaslServer#evaluateResponse(byte[])} method when the user is not set.
*/
@Test
public void userIsNotSet() throws Exception {
mThrown.expect(SaslException.class);
mThrown.expectMessage("Plain authentication failed: No authentication identity provided");
mPlainSaslServer.evaluateResponse(getUserInfo("", "anonymous"));
}
/**
* Tests the {@link PlainSaslServer#evaluateResponse(byte[])} method when the password is not set.
*/
@Test
public void passwordIsNotSet() throws Exception {
mThrown.expect(SaslException.class);
mThrown.expectMessage("Plain authentication failed: No password provided");
mPlainSaslServer.evaluateResponse(getUserInfo("alluxio", ""));
}
/**
* Tests the {@link PlainSaslServer#getAuthorizationID()} method.
*/
@Test
public void authenticationNotComplete() {
mThrown.expect(IllegalStateException.class);
mThrown.expectMessage("PLAIN authentication not completed");
mPlainSaslServer.getAuthorizationID();
}
/**
* Tests the {@link PlainSaslServer#getAuthorizationID()} to retrieve the correct user.
*/
@Test
public void userPasswordReceive() throws Exception {
String testUser = "alluxio";
String password = "anonymous";
mPlainSaslServer.evaluateResponse(getUserInfo(testUser, password));
Assert.assertEquals(testUser, mPlainSaslServer.getAuthorizationID());
}
/**
* A server side callback that is authorized.
*/
private static class MockCallbackHandler implements CallbackHandler {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
AuthorizeCallback ac = null;
for (Callback callback : callbacks) {
if (callback instanceof AuthorizeCallback) {
ac = (AuthorizeCallback) callback;
}
}
ac.setAuthorized(true);
}
}
/**
* A server side callback that is not authorized.
*/
private static class MockCallbackHandlerUnauthorized implements CallbackHandler {
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
AuthorizeCallback ac = null;
for (Callback callback : callbacks) {
if (callback instanceof AuthorizeCallback) {
ac = (AuthorizeCallback) callback;
}
}
ac.setAuthorized(false);
}
}
/**
* Tests the {@link PlainSaslServer#evaluateResponse(byte[])} method when AuthorizeCallback is
* not authorized.
*/
@Test
public void unauthorizedCallback() throws Exception {
String testUser = "alluxio";
String password = "anonymous";
mPlainSaslServer = new PlainSaslServer(new MockCallbackHandlerUnauthorized());
mThrown.expect(SaslException.class);
mThrown.expectMessage("Plain authentication failed: AuthorizeCallback authorized failure");
mPlainSaslServer.evaluateResponse(getUserInfo(testUser, password));
}
}