/*
* Copyright (C) 2006-2016 DLR, Germany
*
* All rights reserved
*
* http://www.rcenvironment.de/
*/
package de.rcenvironment.core.login;
import java.security.cert.X509Certificate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.globus.gsi.OpenSSLKey;
import de.rcenvironment.core.authentication.AuthenticationException;
import de.rcenvironment.core.authentication.AuthenticationService;
import de.rcenvironment.core.authentication.Session;
import de.rcenvironment.core.authentication.User.Type;
import de.rcenvironment.core.configuration.ConfigurationService;
import de.rcenvironment.core.login.internal.Messages;
import de.rcenvironment.core.login.internal.ServiceHandler;
import de.rcenvironment.core.notification.DistributedNotificationService;
/**
* Class handling the login process.
*
* @author Bea Hornef
* @author Doreen Seider
* @author Heinrich Wendel
*/
public abstract class AbstractLogin {
/** Identifier of the notification sent on successful login. */
public static final String LOGIN_NOTIFICATION_ID = "de.rcenvironment.rce.login.success"; //$NON-NLS-1$
protected static final Log LOGGER = LogFactory.getLog(AbstractLogin.class);
private static final String LOGIN_FAILED_1_9 = "Authentication failed due to an invalid certificate or private key"; //$NON-NLS-1$
private static final String LOGIN_FAILED_1_2 = "Authentication failed due to an missing password"; //$NON-NLS-1$
private static final String LOGIN_FAILED_1_3 = "Authentication failed due to an incorrect password"; //$NON-NLS-1$
private static final String LOGIN_FAILED_1_4 = "Authentication failed due to an not matching caertificate - key file"; //$NON-NLS-1$
private static final String LOGIN_FAILED_1_5 =
"Authentication failed cause certificate not signed by trusted certificate authority (CA)."; //$NON-NLS-1$
private static final String LOGIN_FAILED_1_6 = "Authentication failed cause certificate is revoked by its "
+ "certificate authority (CA)."; //$NON-NLS-1$
private static final String LOGIN_FAILED_1_7 = "Authentication failed due to an unknown reason."; //$NON-NLS-1$
private static final String LOGIN_FAILED_2_1 = "Authentication failed due to an invalid password.";
private static final String LOGIN_FAILED_2_2 = "Authentication failed due to an incorrect password or username.";
private static final String LOGIN_SUCCESFULL = "Authentication successful. Session created."; //$NON-NLS-1$
protected AuthenticationService authenticationService;
protected DistributedNotificationService notificationService;
protected ConfigurationService configurationService;
protected LoginConfiguration loginConfiguration;
public AbstractLogin() {
authenticationService = ServiceHandler.getAuthenticationService();
notificationService = ServiceHandler.getNotificationService();
configurationService = ServiceHandler.getConfigurationService();
// note: disabled old configuration loading for 6.0.0 as it is not being used anyway
// loginConfiguration = configurationService.getConfiguration(ServiceHandler.getBundleSymbolicName(), LoginConfiguration.class);
// TODO using default values until reworked or removed
loginConfiguration = new LoginConfiguration();
loginConfiguration.setCertificateFile(configurationService.resolveBundleConfigurationPath(ServiceHandler.getBundleSymbolicName(),
loginConfiguration.getCertificateFile()));
loginConfiguration.setKeyFile(configurationService.resolveBundleConfigurationPath(ServiceHandler.getBundleSymbolicName(),
loginConfiguration.getKeyFile()));
}
/**
* Handles login.
*
* @return True for success, else false.
*/
public final boolean login() {
try {
boolean loginSuccess = false;
// while login not successful try ... harder
while (!loginSuccess) {
LoginInput loginInput = getLoginInput();
loginSuccess = singleUserLogin();
if (loginInput == null) {
break;
}
if (loginInput.getType() == Type.single) {
notificationService.send(LOGIN_NOTIFICATION_ID, "Anonymouslogin"); //$NON-NLS-1$
LOGGER.debug("Using anonymous/default login");
} else if (loginInput.getType() == Type.ldap) {
loginSuccess = ldapLogin(loginInput.getUsernameLDAP(), loginInput.getPassword());
} else if (loginInput.getType() == Type.certificate) {
loginSuccess = certificateLogin(loginInput.getCertificate(), loginInput.getKey(), loginInput.getPassword());
}
}
if (loginSuccess) {
notificationService.send(LOGIN_NOTIFICATION_ID, "Login successful."); //$NON-NLS-1$
return true;
}
// do something with the login info
} catch (AuthenticationException e) {
informUserAboutError(Messages.authenticationFailed + " " //$NON-NLS-1$
+ Messages.certOrKeyIncorrect, e);
LOGGER.error(LOGIN_FAILED_1_9, e);
}
return false;
}
private boolean singleUserLogin() {
Session.create(authenticationService.createUser(loginConfiguration.getValidityInDays()));
return true;
}
/**
*
* Handles login via LDAP.
*
* @return True for success, else false.
*/
private boolean ldapLogin(String userID, String password) {
boolean isLoginSuccessful = false;
AuthenticationService.LDAPAuthenticationResult authenticationResult = authenticationService.
authenticate(userID, password);
if (AuthenticationService.LDAPAuthenticationResult.AUTHENTICATED == authenticationResult) {
isLoginSuccessful = true;
Session.create(userID, loginConfiguration.getValidityInDays());
LOGGER.info(LOGIN_SUCCESFULL);
} else {
isLoginSuccessful = false;
String reasonForFailing;
String reasonForFailingEN;
switch (authenticationResult) {
case PASSWORD__OR_USERNAME_INVALID:
reasonForFailing = Messages.passwordInvalid;
reasonForFailingEN = LOGIN_FAILED_2_1;
break;
case PASSWORD_OR_USERNAME_INCORRECT:
reasonForFailing = Messages.passwordOrUsernameIncorrect;
reasonForFailingEN = LOGIN_FAILED_2_2;
break;
default:
reasonForFailing = Messages.unknownReason;
reasonForFailingEN = LOGIN_FAILED_1_7;
break;
}
informUserAboutError(Messages.authenticationFailed + " " //$NON-NLS-1$
+ reasonForFailing, null);
LOGGER.error(reasonForFailingEN);
}
return isLoginSuccessful;
}
/**
*
* Handles login via certificate.
*
* @return True for success, else false.
* @throws AuthenticationException
*/
private boolean certificateLogin(X509Certificate certificate, OpenSSLKey key, String password)
throws AuthenticationException {
boolean isLoginSuccessful = false;
AuthenticationService.X509AuthenticationResult authenticationResult = authenticationService.authenticate(
certificate, key, password);
if (AuthenticationService.X509AuthenticationResult.AUTHENTICATED == authenticationResult) {
isLoginSuccessful = true;
Session.create(authenticationService.createUser(certificate, loginConfiguration.getValidityInDays()));
LOGGER.info(LOGIN_SUCCESFULL);
} else {
isLoginSuccessful = false;
String reasonForFailing;
String reasonForFailingEN;
switch (authenticationResult) {
case PASSWORD_REQUIRED:
reasonForFailing = Messages.passwordRequiered;
reasonForFailingEN = LOGIN_FAILED_1_2;
break;
case PASSWORD_INCORRECT:
reasonForFailing = Messages.passwordIncorrect;
reasonForFailingEN = LOGIN_FAILED_1_3;
break;
case PRIVATE_KEY_NOT_BELONGS_TO_PUBLIC_KEY:
reasonForFailing = Messages.keyNotMatched;
reasonForFailingEN = LOGIN_FAILED_1_4;
break;
case NOT_SIGNED_BY_TRUSTED_CA:
reasonForFailing = Messages.certNotSigned;
reasonForFailingEN = LOGIN_FAILED_1_5;
break;
case CERTIFICATE_REVOKED:
reasonForFailing = Messages.certRevoced;
reasonForFailingEN = LOGIN_FAILED_1_6;
break;
default:
reasonForFailing = Messages.unknownReason;
reasonForFailingEN = LOGIN_FAILED_1_7;
break;
}
informUserAboutError(Messages.authenticationFailed + " " //$NON-NLS-1$
+ reasonForFailing, null);
LOGGER.error(reasonForFailingEN);
}
return isLoginSuccessful;
}
/**
* Handles logout.
*/
public final void logout() {
try {
Session.getInstance().destroy();
} catch (AuthenticationException e) {
LOGGER.warn("Already logged out."); //$NON-NLS-1$
}
}
/**
* Informs the user about an error.
*
* @param errorMessage The message containing the information about the error.
* @param e {@link Throwable} if there is one.
*/
protected abstract void informUserAboutError(String errorMessage, Throwable e);
/**
* Must be implemented by login provider. Return the chosen login input. Can make use of createLoginInput.
*
* @return the login input getting from the user.
* @throws AuthenticationException Thrown when loading key or path failed.
*/
protected abstract LoginInput getLoginInput() throws AuthenticationException;
/**
* Creates a new {@link LoginInput}.
*
* @param certificatePath Path to the certificate (public key).
* @param keyPath Path to the key (private key).
* @param password The password the private key is encrypted with.
* @throws AuthenticationException Thrown when loading key or path failed.
* @return The generated {@link LoginInput}.
*/
protected LoginInput createLoginInputCertificate(String certificatePath, String keyPath, String password)
throws AuthenticationException {
LoginInput loginInput = null;
OpenSSLKey key = authenticationService.loadKey(keyPath);
X509Certificate cert = authenticationService.loadCertificate(certificatePath);
if (key == null || cert == null) {
throw new AuthenticationException(Messages.keyOrCertCouldNotBeLoaded);
}
loginInput = new LoginInput(cert, key, password);
return loginInput;
}
/**
*
* @param usernameLDAP The username for the LDAP login.
* @param password The password for the login.
* @return The generated {@link LoginInput}.
* @throws AuthenticationException
*/
protected LoginInput createLoginInputLDAP(String usernameLDAP, String password)
throws AuthenticationException {
LoginInput loginInput = new LoginInput(usernameLDAP, password);
return loginInput;
}
}