/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.security.auth;
import com.liferay.portal.events.EventsProcessorUtil;
import com.liferay.portal.kernel.events.Action;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.model.User;
import com.liferay.portal.kernel.security.jaas.PortalPrincipal;
import com.liferay.portal.kernel.security.jaas.PortalRole;
import com.liferay.portal.kernel.service.UserLocalServiceUtil;
import com.liferay.portal.kernel.servlet.HttpMethods;
import com.liferay.portal.kernel.test.rule.AggregateTestRule;
import com.liferay.portal.kernel.test.util.TestPropsValues;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.IntegerWrapper;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.util.PropsKeys;
import com.liferay.portal.kernel.util.ReflectionUtil;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.security.jaas.JAASHelper;
import com.liferay.portal.servlet.MainServlet;
import com.liferay.portal.test.rule.LiferayIntegrationTestRule;
import com.liferay.portal.test.rule.callback.MainServletTestCallback;
import com.liferay.portal.util.PropsValues;
import java.lang.reflect.Field;
import java.security.Principal;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.security.auth.Subject;
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.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
/**
* @author Raymond Augé
*/
public class JAASTest {
@ClassRule
@Rule
public static final AggregateTestRule aggregateTestRule =
new LiferayIntegrationTestRule();
@Before
public void setUp() throws Exception {
_jaasAuthTypeField = ReflectionUtil.getDeclaredField(
PropsValues.class, "PORTAL_JAAS_AUTH_TYPE");
_jaasAuthType = (String)_jaasAuthTypeField.get(null);
_jaasEnabledField = ReflectionUtil.getDeclaredField(
PropsValues.class, "PORTAL_JAAS_ENABLE");
_jaasEnabled = (Boolean)_jaasEnabledField.get(null);
_jaasEnabledField.set(null, true);
Configuration.setConfiguration(new JAASConfiguration());
_user = TestPropsValues.getUser();
}
@After
public void tearDown() throws Exception {
Configuration.setConfiguration(null);
_jaasAuthTypeField.set(null, _jaasAuthType);
_jaasEnabledField.set(null, _jaasEnabled);
}
@Test
public void testGetUser() throws Exception {
_jaasAuthTypeField.set(null, "screenName");
final IntegerWrapper counter = new IntegerWrapper();
JAASHelper jaasHelper = JAASHelper.getInstance();
JAASHelper.setInstance(
new JAASHelper() {
@Override
protected long doGetJaasUserId(long companyId, String name)
throws PortalException {
try {
return super.doGetJaasUserId(companyId, name);
}
finally {
counter.increment();
}
}
});
MainServlet mainServlet = MainServletTestCallback.getMainServlet();
MockHttpServletRequest mockHttpServletRequest =
new MockHttpServletRequest(
mainServlet.getServletContext(), HttpMethods.GET,
StringPool.SLASH);
mockHttpServletRequest.setRemoteUser(
String.valueOf(_user.getScreenName()));
try {
User user = PortalUtil.getUser(mockHttpServletRequest);
Assert.assertEquals(1, counter.getValue());
Assert.assertEquals(_user.getUserId(), user.getUserId());
user = PortalUtil.getUser(mockHttpServletRequest);
Assert.assertEquals(1, counter.getValue());
Assert.assertEquals(_user.getUserId(), user.getUserId());
}
finally {
JAASHelper.setInstance(jaasHelper);
}
}
@Test
public void testLoginEmailAddressWithEmailAddress() throws Exception {
_jaasAuthTypeField.set(null, "emailAddress");
LoginContext loginContext = getLoginContext(
_user.getEmailAddress(), _user.getPassword());
loginContext.login();
validateSubject(loginContext.getSubject(), _user.getEmailAddress());
}
@Test
public void testLoginEmailAddressWithLogin() throws Exception {
_jaasAuthTypeField.set(null, "login");
LoginContext loginContext = getLoginContext(
_user.getEmailAddress(), _user.getPassword());
loginContext.login();
validateSubject(loginContext.getSubject(), _user.getEmailAddress());
}
@Test
public void testLoginEmailAddressWithScreenName() throws Exception {
_jaasAuthTypeField.set(null, "screenName");
LoginContext loginContext = getLoginContext(
_user.getEmailAddress(), _user.getPassword());
try {
loginContext.login();
Assert.fail();
}
catch (Exception e) {
}
}
@Test
public void testLoginEmailAddressWithUserId() throws Exception {
_jaasAuthTypeField.set(null, "userId");
LoginContext loginContext = getLoginContext(
_user.getEmailAddress(), _user.getPassword());
try {
loginContext.login();
Assert.fail();
}
catch (Exception e) {
}
}
@Test
public void testLoginScreenNameWithEmailAddress() throws Exception {
_jaasAuthTypeField.set(null, "emailAddress");
LoginContext loginContext = getLoginContext(
_user.getScreenName(), _user.getPassword());
try {
loginContext.login();
Assert.fail();
}
catch (Exception e) {
}
}
@Test
public void testLoginScreenNameWithLogin() throws Exception {
_jaasAuthTypeField.set(null, "login");
LoginContext loginContext = getLoginContext(
_user.getScreenName(), _user.getPassword());
try {
loginContext.login();
Assert.fail();
}
catch (Exception e) {
}
}
@Test
public void testLoginScreenNameWithScreenName() throws Exception {
_jaasAuthTypeField.set(null, "screenName");
LoginContext loginContext = getLoginContext(
_user.getScreenName(), _user.getPassword());
loginContext.login();
validateSubject(loginContext.getSubject(), _user.getScreenName());
}
@Test
public void testLoginScreenNameWithUserId() throws Exception {
_jaasAuthTypeField.set(null, "userId");
LoginContext loginContext = getLoginContext(
_user.getScreenName(), _user.getPassword());
try {
loginContext.login();
Assert.fail();
}
catch (Exception e) {
}
}
@Test
public void testLoginUserIdWithEmailAddress() throws Exception {
_jaasAuthTypeField.set(null, "emailAddress");
LoginContext loginContext = getLoginContext(
String.valueOf(_user.getUserId()), _user.getPassword());
try {
loginContext.login();
Assert.fail();
}
catch (Exception e) {
}
}
@Test
public void testLoginUserIdWithLogin() throws Exception {
_jaasAuthTypeField.set(null, "login");
LoginContext loginContext = getLoginContext(
String.valueOf(_user.getUserId()), _user.getPassword());
try {
loginContext.login();
Assert.fail();
}
catch (Exception e) {
}
}
@Test
public void testLoginUserIdWithScreenName() throws Exception {
_jaasAuthTypeField.set(null, "screenName");
LoginContext loginContext = getLoginContext(
String.valueOf(_user.getUserId()), _user.getPassword());
try {
loginContext.login();
Assert.fail();
}
catch (Exception e) {
}
}
@Test
public void testLoginUserIdWithUserId() throws Exception {
_jaasAuthTypeField.set(null, "userId");
LoginContext loginContext = getLoginContext(
String.valueOf(_user.getUserId()), _user.getPassword());
loginContext.login();
validateSubject(
loginContext.getSubject(), String.valueOf(_user.getUserId()));
}
@Test
public void testProcessLoginEvents() throws Exception {
MainServlet mainServlet = MainServletTestCallback.getMainServlet();
Date lastLoginDate = _user.getLastLoginDate();
MockHttpServletRequest mockHttpServletRequest =
new MockHttpServletRequest(
mainServlet.getServletContext(), HttpMethods.GET,
StringPool.SLASH);
mockHttpServletRequest.setRemoteUser(String.valueOf(_user.getUserId()));
JAASAction preJAASAction = new JAASAction();
JAASAction postJAASAction = new JAASAction();
try {
EventsProcessorUtil.registerEvent(
PropsKeys.LOGIN_EVENTS_PRE, preJAASAction);
EventsProcessorUtil.registerEvent(
PropsKeys.LOGIN_EVENTS_POST, postJAASAction);
mainServlet.service(
mockHttpServletRequest, new MockHttpServletResponse());
Assert.assertTrue(preJAASAction.isRan());
Assert.assertTrue(postJAASAction.isRan());
_user = UserLocalServiceUtil.getUser(_user.getUserId());
Assert.assertFalse(lastLoginDate.after(_user.getLastLoginDate()));
}
finally {
EventsProcessorUtil.unregisterEvent(
PropsKeys.LOGIN_EVENTS_PRE, postJAASAction);
EventsProcessorUtil.unregisterEvent(
PropsKeys.LOGIN_EVENTS_POST, postJAASAction);
}
}
protected LoginContext getLoginContext(String name, String password)
throws Exception {
return new LoginContext(
"PortalRealm", new JAASCallbackHandler(name, password));
}
protected void validateSubject(Subject subject, String userIdString) {
Assert.assertNotNull(subject);
Set<Principal> userPrincipals = subject.getPrincipals();
Assert.assertNotNull(userPrincipals);
Iterator<Principal> iterator = userPrincipals.iterator();
Assert.assertTrue(iterator.hasNext());
while (iterator.hasNext()) {
Principal principal = iterator.next();
if (principal instanceof PortalRole) {
PortalRole portalRole = (PortalRole)principal;
Assert.assertEquals("users", portalRole.getName());
}
else {
PortalPrincipal portalPrincipal = (PortalPrincipal)principal;
Assert.assertEquals(userIdString, portalPrincipal.getName());
}
}
}
private String _jaasAuthType;
private Field _jaasAuthTypeField;
private Boolean _jaasEnabled;
private Field _jaasEnabledField;
private User _user;
private static class JAASAction extends Action {
public boolean isRan() {
return _ran;
}
@Override
public void run(
HttpServletRequest request, HttpServletResponse response) {
_ran = true;
}
private boolean _ran;
}
private static class JAASCallbackHandler implements CallbackHandler {
public JAASCallbackHandler(String name, String password) {
_name = name;
_password = password;
}
@Override
public void handle(Callback[] callbacks)
throws UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof NameCallback) {
NameCallback nameCallback = (NameCallback)callback;
nameCallback.setName(_name);
}
else if (callback instanceof PasswordCallback) {
String password = GetterUtil.getString(_password);
PasswordCallback passwordCallback =
(PasswordCallback)callback;
passwordCallback.setPassword(password.toCharArray());
}
else {
throw new UnsupportedCallbackException(callback);
}
}
}
private final String _name;
private final String _password;
}
private static class JAASConfiguration extends Configuration {
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
AppConfigurationEntry[] appConfigurationEntries =
new AppConfigurationEntry[1];
Map<String, Object> options = new HashMap<>();
options.put("debug", Boolean.TRUE);
appConfigurationEntries[0] = new AppConfigurationEntry(
"com.liferay.portal.kernel.security.jaas.PortalLoginModule",
LoginModuleControlFlag.REQUIRED, options);
return appConfigurationEntries;
}
}
}