/**
* Waffle (https://github.com/Waffle/waffle)
*
* Copyright (c) 2010-2017 Application Security, Inc.
*
* All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse
* Public License v1.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v10.html.
*
* Contributors: Application Security, Inc.
*/
package waffle.windows.auth;
import java.util.Base64;
import org.assertj.core.api.Assertions;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.Advapi32Util;
import com.sun.jna.platform.win32.LMAccess;
import com.sun.jna.platform.win32.LMErr;
import com.sun.jna.platform.win32.LMJoin;
import com.sun.jna.platform.win32.Netapi32;
import com.sun.jna.platform.win32.Netapi32Util;
import com.sun.jna.platform.win32.Sspi;
import com.sun.jna.platform.win32.Sspi.SecBufferDesc;
import waffle.mock.MockWindowsAccount;
import waffle.windows.auth.impl.WindowsAccountImpl;
import waffle.windows.auth.impl.WindowsAuthProviderImpl;
import waffle.windows.auth.impl.WindowsCredentialsHandleImpl;
import waffle.windows.auth.impl.WindowsSecurityContextImpl;
/**
* The Class WindowsAuthProviderTests.
*
* @author dblock[at]dblock[dot]org
*/
public class WindowsAuthProviderTests {
/** The Constant LOGGER. */
private static final Logger LOGGER = LoggerFactory.getLogger(WindowsAuthProviderTests.class);
/**
* Test logon guest user.
*/
// TODO This was commented out, uncommented and ignore until I can determine if this is valid
@Ignore
@Test
public void testLogonGuestUser() {
final IWindowsAuthProvider prov = new WindowsAuthProviderImpl();
final IWindowsIdentity identity = prov.logonUser("garbage", "garbage");
WindowsAuthProviderTests.LOGGER.info("Fqn: {}", identity.getFqn());
WindowsAuthProviderTests.LOGGER.info("Guest: {}", Boolean.valueOf(identity.isGuest()));
Assert.assertTrue(identity.getFqn().endsWith("\\Guest"));
Assert.assertTrue(identity.isGuest());
identity.dispose();
}
/**
* Test logon user.
*/
@Test
public void testLogonUser() {
final LMAccess.USER_INFO_1 userInfo = new LMAccess.USER_INFO_1();
userInfo.usri1_name = new WString("WaffleTestUser").toString();
userInfo.usri1_password = new WString("!WAFFLEP$$Wrd0").toString();
userInfo.usri1_priv = LMAccess.USER_PRIV_USER;
// ignore test if not able to add user (need to be administrator to do this).
Assume.assumeTrue(LMErr.NERR_Success == Netapi32.INSTANCE.NetUserAdd(null, 1, userInfo, null));
try {
final IWindowsAuthProvider prov = new WindowsAuthProviderImpl();
final IWindowsIdentity identity = prov.logonUser(userInfo.usri1_name.toString(),
userInfo.usri1_password.toString());
Assert.assertTrue(identity.getFqn().endsWith("\\" + userInfo.usri1_name.toString()));
Assert.assertFalse(identity.isGuest());
identity.dispose();
} finally {
Assert.assertEquals(LMErr.NERR_Success, Netapi32.INSTANCE.NetUserDel(null, userInfo.usri1_name.toString()));
}
}
/**
* Test impersonate logged on user.
*/
@Test
public void testImpersonateLoggedOnUser() {
final LMAccess.USER_INFO_1 userInfo = new LMAccess.USER_INFO_1();
userInfo.usri1_name = new WString(MockWindowsAccount.TEST_USER_NAME).toString();
userInfo.usri1_password = new WString(MockWindowsAccount.TEST_PASSWORD).toString();
userInfo.usri1_priv = LMAccess.USER_PRIV_USER;
// ignore test if not able to add user (need to be administrator to do this).
Assume.assumeTrue(LMErr.NERR_Success == Netapi32.INSTANCE.NetUserAdd(null, 1, userInfo, null));
try {
final IWindowsAuthProvider prov = new WindowsAuthProviderImpl();
final IWindowsIdentity identity = prov.logonUser(userInfo.usri1_name.toString(),
userInfo.usri1_password.toString());
final IWindowsImpersonationContext ctx = identity.impersonate();
Assert.assertTrue(userInfo.usri1_name.toString().equals(Advapi32Util.getUserName()));
ctx.revertToSelf();
Assert.assertFalse(userInfo.usri1_name.toString().equals(Advapi32Util.getUserName()));
identity.dispose();
} finally {
Assert.assertEquals(LMErr.NERR_Success, Netapi32.INSTANCE.NetUserDel(null, userInfo.usri1_name.toString()));
}
}
/**
* Test get current computer.
*/
@Test
public void testGetCurrentComputer() {
final IWindowsAuthProvider prov = new WindowsAuthProviderImpl();
final IWindowsComputer computer = prov.getCurrentComputer();
WindowsAuthProviderTests.LOGGER.info(computer.getComputerName());
Assertions.assertThat(computer.getComputerName().length()).isGreaterThan(0);
WindowsAuthProviderTests.LOGGER.info(computer.getJoinStatus());
WindowsAuthProviderTests.LOGGER.info(computer.getMemberOf());
final String[] localGroups = computer.getGroups();
Assert.assertNotNull(localGroups);
Assertions.assertThat(localGroups.length).isGreaterThan(0);
for (final String localGroup : localGroups) {
WindowsAuthProviderTests.LOGGER.info(" {}", localGroup);
}
}
/**
* Test get domains.
*/
@Test
public void testGetDomains() {
if (Netapi32Util.getJoinStatus() != LMJoin.NETSETUP_JOIN_STATUS.NetSetupDomainName) {
return;
}
final IWindowsAuthProvider prov = new WindowsAuthProviderImpl();
final IWindowsDomain[] domains = prov.getDomains();
Assert.assertNotNull(domains);
for (final IWindowsDomain domain : domains) {
WindowsAuthProviderTests.LOGGER.info("{}: {}", domain.getFqn(), domain.getTrustDirectionString());
}
}
/**
* Test accept security token.
*/
@Test
public void testAcceptSecurityToken() {
final String securityPackage = "Negotiate";
final String targetName = "localhost";
IWindowsCredentialsHandle clientCredentials = null;
WindowsSecurityContextImpl clientContext = null;
IWindowsSecurityContext serverContext = null;
try {
// client credentials handle
clientCredentials = WindowsCredentialsHandleImpl.getCurrent(securityPackage);
clientCredentials.initialize();
// initial client security context
clientContext = new WindowsSecurityContextImpl();
clientContext.setPrincipalName(WindowsAccountImpl.getCurrentUsername());
clientContext.setCredentialsHandle(clientCredentials);
clientContext.setSecurityPackage(securityPackage);
clientContext.initialize(null, null, targetName);
// accept on the server
final WindowsAuthProviderImpl provider = new WindowsAuthProviderImpl();
final String connectionId = "testConnection-" + Thread.currentThread().getId();
do {
// accept the token on the server
serverContext = provider.acceptSecurityToken(connectionId, clientContext.getToken(), securityPackage);
if (serverContext != null && serverContext.isContinue()) {
// initialize on the client
final SecBufferDesc continueToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN,
serverContext.getToken());
clientContext.initialize(clientContext.getHandle(), continueToken, targetName);
WindowsAuthProviderTests.LOGGER.info("Token: {}",
Base64.getEncoder().encodeToString(serverContext.getToken()));
}
} while (serverContext != null && serverContext.isContinue());
if (serverContext != null) {
Assertions.assertThat(serverContext.getIdentity().getFqn().length()).isGreaterThan(0);
WindowsAuthProviderTests.LOGGER.info(serverContext.getIdentity().getFqn());
for (final IWindowsAccount group : serverContext.getIdentity().getGroups()) {
WindowsAuthProviderTests.LOGGER.info(" {}", group.getFqn());
}
}
} finally {
if (serverContext != null) {
serverContext.dispose();
}
if (clientContext != null) {
clientContext.dispose();
}
if (clientCredentials != null) {
clientCredentials.dispose();
}
}
}
/**
* Test security contexts expire.
*
* @throws InterruptedException
* the interrupted exception
*/
@Test
public void testSecurityContextsExpire() throws InterruptedException {
final String securityPackage = "Negotiate";
IWindowsCredentialsHandle clientCredentials = null;
WindowsSecurityContextImpl clientContext = null;
IWindowsSecurityContext serverContext = null;
try {
// client credentials handle
clientCredentials = WindowsCredentialsHandleImpl.getCurrent(securityPackage);
clientCredentials.initialize();
// initial client security context
clientContext = new WindowsSecurityContextImpl();
clientContext.setPrincipalName(WindowsAccountImpl.getCurrentUsername());
clientContext.setCredentialsHandle(clientCredentials);
clientContext.setSecurityPackage(securityPackage);
clientContext.initialize(null, null, WindowsAccountImpl.getCurrentUsername());
// accept on the server
final WindowsAuthProviderImpl provider = new WindowsAuthProviderImpl(1);
final int max = 100;
for (int i = 0; i < max; i++) {
Thread.sleep(25);
final String connectionId = "testConnection_" + i;
serverContext = provider.acceptSecurityToken(connectionId, clientContext.getToken(), securityPackage);
Assertions.assertThat(provider.getContinueContextsSize()).isGreaterThan(0);
}
WindowsAuthProviderTests.LOGGER.info("Cached security contexts: {}",
Integer.valueOf(provider.getContinueContextsSize()));
Assert.assertFalse(max == provider.getContinueContextsSize());
} finally {
if (serverContext != null) {
serverContext.dispose();
}
if (clientContext != null) {
clientContext.dispose();
}
if (clientCredentials != null) {
clientCredentials.dispose();
}
}
}
/**
* Test accept and impersonate security token.
*/
@Test
public void testAcceptAndImpersonateSecurityToken() {
final String securityPackage = "Negotiate";
final String targetName = "localhost";
IWindowsCredentialsHandle clientCredentials = null;
WindowsSecurityContextImpl clientContext = null;
IWindowsSecurityContext serverContext = null;
try {
// client credentials handle
clientCredentials = WindowsCredentialsHandleImpl.getCurrent(securityPackage);
clientCredentials.initialize();
// initial client security context
clientContext = new WindowsSecurityContextImpl();
clientContext.setPrincipalName(WindowsAccountImpl.getCurrentUsername());
clientContext.setCredentialsHandle(clientCredentials);
clientContext.setSecurityPackage(securityPackage);
clientContext.initialize(null, null, targetName);
// accept on the server
final WindowsAuthProviderImpl provider = new WindowsAuthProviderImpl();
final String connectionId = "testConnection";
do {
// accept the token on the server
serverContext = provider.acceptSecurityToken(connectionId, clientContext.getToken(), securityPackage);
if (serverContext != null && serverContext.isContinue()) {
// initialize on the client
final SecBufferDesc continueToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN,
serverContext.getToken());
clientContext.initialize(clientContext.getHandle(), continueToken, targetName);
}
} while (serverContext != null && serverContext.isContinue());
if (serverContext != null) {
Assertions.assertThat(serverContext.getIdentity().getFqn().length()).isGreaterThan(0);
final IWindowsImpersonationContext impersonationCtx = serverContext.impersonate();
impersonationCtx.revertToSelf();
WindowsAuthProviderTests.LOGGER.info(serverContext.getIdentity().getFqn());
for (final IWindowsAccount group : serverContext.getIdentity().getGroups()) {
WindowsAuthProviderTests.LOGGER.info(" {}", group.getFqn());
}
}
} finally {
if (serverContext != null) {
serverContext.dispose();
}
if (clientContext != null) {
clientContext.dispose();
}
if (clientCredentials != null) {
clientCredentials.dispose();
}
}
}
}