/**
* Copyright (c) 2014--2015 Red Hat, Inc.
*
* This software is licensed to you under the GNU General Public License,
* version 2 (GPLv2). There is NO WARRANTY for this software, express or
* implied, including the implied warranties of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. You should have received a copy of GPLv2
* along with this software; if not, see
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* Red Hat trademarks are not licensed under GPLv2. No permission is
* granted to use or replicate Red Hat trademarks that are incorporated
* in this software or its documentation.
*/
package com.redhat.rhn.frontend.action;
import com.redhat.rhn.common.db.WrappedSQLException;
import com.redhat.rhn.common.db.datasource.DataResult;
import com.redhat.rhn.common.db.datasource.ModeFactory;
import com.redhat.rhn.common.db.datasource.SelectMode;
import com.redhat.rhn.common.hibernate.HibernateFactory;
import com.redhat.rhn.common.hibernate.LookupException;
import com.redhat.rhn.common.messaging.MessageQueue;
import com.redhat.rhn.domain.common.SatConfigFactory;
import com.redhat.rhn.domain.org.Org;
import com.redhat.rhn.domain.org.OrgFactory;
import com.redhat.rhn.domain.org.usergroup.OrgUserExtGroup;
import com.redhat.rhn.domain.org.usergroup.UserExtGroup;
import com.redhat.rhn.domain.org.usergroup.UserGroupFactory;
import com.redhat.rhn.domain.role.Role;
import com.redhat.rhn.domain.server.ServerGroup;
import com.redhat.rhn.domain.user.User;
import com.redhat.rhn.domain.user.UserFactory;
import com.redhat.rhn.frontend.events.UpdateErrataCacheEvent;
import com.redhat.rhn.frontend.servlets.PxtSessionDelegateFactory;
import com.redhat.rhn.manager.satellite.SystemCommandExecutor;
import com.redhat.rhn.manager.user.CreateUserCommand;
import com.redhat.rhn.manager.user.UpdateUserCommand;
import com.redhat.rhn.manager.user.UserManager;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.StopWatch;
import org.apache.log4j.Logger;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMessage;
import org.apache.struts.action.ActionMessages;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* LoginHelper
* @version $Rev$
*/
public class LoginHelper {
private static Logger log = Logger.getLogger(LoginHelper.class);
private static final String DEFAULT_KERB_USER_PASSWORD = "0";
/**
* Utility classes can't be instantiated.
*/
private LoginHelper() {
}
/**
* check whether we can login an externally authenticated user
* @param request request
* @param messages messages
* @param errors errors
* @return user, if externally authenticated
*/
public static User checkExternalAuthentication(HttpServletRequest request,
ActionMessages messages,
ActionErrors errors) {
String remoteUserString = request.getRemoteUser();
User remoteUser = null;
if (remoteUserString != null) {
String firstname = decodeFromIso88591(
(String) request.getAttribute("REMOTE_USER_FIRSTNAME"), "");
String lastname = decodeFromIso88591(
(String) request.getAttribute("REMOTE_USER_LASTNAME"), "");
String email = decodeFromIso88591(
(String) request.getAttribute("REMOTE_USER_EMAIL"), null);
Set<String> extGroups = getExtGroups(request);
Set<Role> roles = getRolesFromExtGroups(extGroups);
try {
remoteUser = UserFactory.lookupByLogin(remoteUserString);
if (remoteUser.isDisabled()) {
errors.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("account.user.disabled",
new String[] {remoteUserString}));
remoteUser = null;
}
if (remoteUser != null) {
UpdateUserCommand updateCmd = new UpdateUserCommand(remoteUser);
if (!StringUtils.isEmpty(firstname)) {
updateCmd.setFirstNames(firstname);
}
if (!StringUtils.isEmpty(lastname)) {
updateCmd.setLastName(lastname);
}
if (!StringUtils.isEmpty(email)) {
updateCmd.setEmail(email);
}
updateCmd.setTemporaryRoles(roles);
updateCmd.updateUser();
log.warn("Externally authenticated login " + remoteUserString +
" (" + firstname + " " + lastname + ")");
}
}
catch (LookupException le) {
Org newUserOrg = null;
Boolean useOrgUnit = SatConfigFactory.getSatConfigBooleanValue(
SatConfigFactory.EXT_AUTH_USE_ORGUNIT);
if (useOrgUnit) {
String orgUnitString =
(String) request.getAttribute("REMOTE_USER_ORGUNIT");
newUserOrg = OrgFactory.lookupByName(orgUnitString);
if (newUserOrg == null) {
log.error("Cannot find organization with name: " + orgUnitString);
}
}
if (newUserOrg == null) {
Long defaultOrgId = SatConfigFactory.getSatConfigLongValue(
SatConfigFactory.EXT_AUTH_DEFAULT_ORGID);
if (defaultOrgId != null) {
newUserOrg = OrgFactory.lookupById(defaultOrgId);
if (newUserOrg == null) {
log.error("Cannot find organization with id: " + defaultOrgId);
}
}
}
if (newUserOrg != null) {
Set<ServerGroup> sgs = getSgsFromExtGroups(extGroups, newUserOrg);
try {
CreateUserCommand createCmd = new CreateUserCommand();
createCmd.setLogin(remoteUserString);
// set a password, that cannot really be used
createCmd.setRawPassword(DEFAULT_KERB_USER_PASSWORD);
createCmd.setFirstNames(firstname);
createCmd.setLastName(lastname);
createCmd.setEmail(email);
createCmd.setOrg(newUserOrg);
createCmd.setTemporaryRoles(roles);
createCmd.setServerGroups(sgs);
createCmd.validate();
createCmd.storeNewUser();
remoteUser = createCmd.getUser();
log.warn("Externally authenticated login " + remoteUserString +
" (" + firstname + " " + lastname + ") created in " +
newUserOrg.getName() + ".");
}
catch (WrappedSQLException wse) {
log.error("Creation of user failed with: " + wse.getMessage());
HibernateFactory.rollbackTransaction();
}
}
if (remoteUser != null &&
remoteUser.getPassword().equals(DEFAULT_KERB_USER_PASSWORD)) {
messages.add(ActionMessages.GLOBAL_MESSAGE,
new ActionMessage("message.kerbuserlogged",
new String[] {remoteUserString}));
}
}
}
return remoteUser;
}
private static String decodeFromIso88591(String string, String defaultString) {
try {
if (string != null) {
return new String(string.getBytes("ISO8859-1"), "UTF-8");
}
}
catch (UnsupportedEncodingException e) {
log.warn("Unable to decode: " + string);
}
return defaultString;
}
private static Set<Role> getRolesFromExtGroups(Set<String> groupNames) {
Set<Role> roles = new HashSet<Role>();
for (String extGroupName : groupNames) {
UserExtGroup extGroup = UserGroupFactory.lookupExtGroupByLabel(extGroupName);
if (extGroup == null) {
log.info("No role mapping defined for external group '" + extGroupName +
"'.");
continue;
}
roles.addAll(extGroup.getRoles());
}
return roles;
}
private static Set<ServerGroup> getSgsFromExtGroups(Set<String> groupNames, Org org) {
Set<ServerGroup> sgs = new HashSet<ServerGroup>();
for (String extGroupName : groupNames) {
OrgUserExtGroup extGroup =
UserGroupFactory.lookupOrgExtGroupByLabelAndOrg(extGroupName, org);
if (extGroup == null) {
log.info("No sg mapping defined for external group '" + extGroupName +
"'.");
continue;
}
sgs.addAll(extGroup.getServerGroups());
}
return sgs;
}
private static Set<String> getExtGroups(HttpServletRequest requestIn) {
Set<String> extGroups = new HashSet<String>();
Long nGroups = null;
String nGroupsStr = (String) requestIn.getAttribute("REMOTE_USER_GROUP_N");
if (nGroupsStr != null) {
try {
nGroups = Long.parseLong(nGroupsStr);
}
catch (NumberFormatException nfe) {
// do nothing, nGroups stays null
}
}
if (nGroups == null) {
log.warn("REMOTE_USER_GROUP_N not set!");
return extGroups;
}
for (int i = 1; i <= nGroups; i++) {
String extGroupName = (String) requestIn.getAttribute("REMOTE_USER_GROUP_" + i);
if (extGroupName == null) {
log.warn("REMOTE_USER_GROUP_" + i + " not set!");
continue;
}
extGroups.add(extGroupName);
}
log.warn("REMOTE_USER_GROUP_" + nGroupsStr + ": " +
StringUtils.join(extGroups.toArray(), ";"));
return extGroups;
}
/** static method shared by LoginAction and LoginSetupAction
* @param request actual request
* @param response actual reponse
* @param user logged in user
* @return returns true, if redirect
*/
public static boolean successfulLogin(HttpServletRequest request,
HttpServletResponse response, User user) {
// set last logged in
user.setLastLoggedIn(new Date());
UserManager.storeUser(user);
// update session with actual user
PxtSessionDelegateFactory.getInstance().newPxtSessionDelegate().
updateWebUserId(request, response, user.getId());
LoginHelper.publishUpdateErrataCacheEvent(user.getOrg());
// redirect, if url_bounce set
String urlBounce = request.getParameter("url_bounce");
String reqMethod = request.getParameter("request_method");
urlBounce = LoginAction.updateUrlBounce(urlBounce, reqMethod);
try {
if (urlBounce != null) {
log.info("redirect: " + urlBounce);
response.sendRedirect(urlBounce);
return true;
}
}
catch (IOException e) {
e.printStackTrace();
}
return false;
}
/**
* @param orgIn
*/
private static void publishUpdateErrataCacheEvent(Org orgIn) {
StopWatch sw = new StopWatch();
if (log.isDebugEnabled()) {
log.debug("Updating errata cache");
sw.start();
}
UpdateErrataCacheEvent uece = new
UpdateErrataCacheEvent(UpdateErrataCacheEvent.TYPE_ORG);
uece.setOrgId(orgIn.getId());
MessageQueue.publish(uece);
if (log.isDebugEnabled()) {
sw.stop();
log.debug("Finished Updating errata cache. Took [" +
sw.getTime() + "]");
}
}
/**
* @return returns whether installed schema version matches schema version of DB
*/
public static Boolean isSchemaUpgradeRequired() {
String rpmSchemaVersion = getRpmSchemaVersion("satellite-schema");
if (rpmSchemaVersion == null) {
rpmSchemaVersion = getRpmSchemaVersion("spacewalk-schema");
}
SelectMode m = ModeFactory.getMode("General_queries", "installed_schema_version");
DataResult<HashMap> dr = m.execute();
String installedSchemaVersion = null;
if (dr.size() > 0) {
installedSchemaVersion = (String) dr.get(0).get("version");
}
if (log.isDebugEnabled()) {
log.debug("RPM version of schema: " +
(rpmSchemaVersion == null ? "null" : rpmSchemaVersion));
log.debug("Version of installed database schema: " +
(installedSchemaVersion == null ? "null" : installedSchemaVersion));
}
return rpmSchemaVersion != null && installedSchemaVersion != null &&
!rpmSchemaVersion.equals(installedSchemaVersion);
}
private static String getRpmSchemaVersion(String schemaName) {
String[] rpmCommand = new String[4];
rpmCommand[0] = "rpm";
rpmCommand[1] = "-q";
rpmCommand[2] = "--qf=%{VERSION}-%{RELEASE}";
rpmCommand[3] = schemaName;
SystemCommandExecutor ce = new SystemCommandExecutor();
return ce.execute(rpmCommand) == 0 ?
ce.getLastCommandOutput().replace("\n", "") : null;
}
}