package edu.harvard.iq.dataverse;
import edu.harvard.iq.dataverse.authorization.AuthenticationProvider;
import edu.harvard.iq.dataverse.authorization.AuthenticationProviderDisplayInfo;
import edu.harvard.iq.dataverse.authorization.AuthenticationRequest;
import edu.harvard.iq.dataverse.authorization.AuthenticationResponse;
import edu.harvard.iq.dataverse.authorization.AuthenticationServiceBean;
import edu.harvard.iq.dataverse.authorization.CredentialsAuthenticationProvider;
import edu.harvard.iq.dataverse.authorization.exceptions.AuthenticationFailedException;
import edu.harvard.iq.dataverse.authorization.providers.builtin.BuiltinUserServiceBean;
import edu.harvard.iq.dataverse.authorization.users.AuthenticatedUser;
import edu.harvard.iq.dataverse.settings.SettingsServiceBean;
import edu.harvard.iq.dataverse.util.BundleUtil;
import edu.harvard.iq.dataverse.util.JsfHelper;
import static edu.harvard.iq.dataverse.util.JsfHelper.JH;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.event.AjaxBehaviorEvent;
import javax.faces.view.ViewScoped;
import javax.inject.Inject;
import javax.inject.Named;
/**
*
* @author xyang
* @author Michael Bar-Sinai
*/
@ViewScoped
@Named("LoginPage")
public class LoginPage implements java.io.Serializable {
private static final Logger logger = Logger.getLogger(LoginPage.class.getName());
public static class FilledCredential {
CredentialsAuthenticationProvider.Credential credential;
String value;
public FilledCredential() {
}
public FilledCredential(CredentialsAuthenticationProvider.Credential credential, String value) {
this.credential = credential;
this.value = value;
}
public CredentialsAuthenticationProvider.Credential getCredential() {
return credential;
}
public void setCredential(CredentialsAuthenticationProvider.Credential credential) {
this.credential = credential;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
public enum EditMode {LOGIN, SUCCESS, FAILED};
@Inject DataverseSession session;
@EJB
DataverseServiceBean dataverseService;
@EJB
BuiltinUserServiceBean dataverseUserService;
@EJB
UserServiceBean userService;
@EJB
AuthenticationServiceBean authSvc;
@EJB
SettingsServiceBean settingsService;
@Inject
DataverseRequestServiceBean dvRequestService;
private String credentialsAuthProviderId;
private List<FilledCredential> filledCredentials;
private String redirectPage = "dataverse.xhtml";
public void init() {
Iterator<String> credentialsIterator = authSvc.getAuthenticationProviderIdsOfType( CredentialsAuthenticationProvider.class ).iterator();
if ( credentialsIterator.hasNext() ) {
setCredentialsAuthProviderId(credentialsIterator.next());
}
resetFilledCredentials(null);
}
public boolean isAuthenticationProvidersAvailable() {
return ! authSvc.getAuthenticationProviderIds().isEmpty();
}
public List<AuthenticationProviderDisplayInfo> listCredentialsAuthenticationProviders() {
List<AuthenticationProviderDisplayInfo> infos = new LinkedList<>();
for ( String id : authSvc.getAuthenticationProviderIdsOfType( CredentialsAuthenticationProvider.class ) ) {
AuthenticationProvider authenticationProvider = authSvc.getAuthenticationProvider(id);
infos.add( authenticationProvider.getInfo());
}
return infos;
}
public List<AuthenticationProviderDisplayInfo> listAuthenticationProviders() {
List<AuthenticationProviderDisplayInfo> infos = new LinkedList<>();
for ( String id : authSvc.getAuthenticationProviderIds() ) {
AuthenticationProvider authenticationProvider = authSvc.getAuthenticationProvider(id);
infos.add( authenticationProvider.getInfo());
}
return infos;
}
public CredentialsAuthenticationProvider selectedCredentialsProvider() {
return (CredentialsAuthenticationProvider) authSvc.getAuthenticationProvider(getCredentialsAuthProviderId());
}
public boolean validatePassword(String username, String password) {
return false;
}
public String login() {
AuthenticationRequest authReq = new AuthenticationRequest();
List<FilledCredential> filledCredentialsList = getFilledCredentials();
if ( filledCredentialsList == null ) {
logger.info("Credential list is null!");
return null;
}
for ( FilledCredential fc : filledCredentialsList ) {
if(fc.getValue()==null || fc.getValue().isEmpty()){
JH.addMessage(FacesMessage.SEVERITY_ERROR, "Please enter a "+fc.getCredential().getTitle());
}
authReq.putCredential(fc.getCredential().getTitle(), fc.getValue());
}
authReq.setIpAddress( dvRequestService.getDataverseRequest().getSourceAddress() );
try {
AuthenticatedUser r = authSvc.authenticate(credentialsAuthProviderId, authReq);
logger.log(Level.FINE, "User authenticated: {0}", r.getEmail());
session.setUser(r);
if ("dataverse.xhtml".equals(redirectPage)) {
redirectPage = redirectPage + "&alias=" + dataverseService.findRootDataverse().getAlias();
}
try {
redirectPage = URLDecoder.decode(redirectPage, "UTF-8");
} catch (UnsupportedEncodingException ex) {
Logger.getLogger(LoginPage.class.getName()).log(Level.SEVERE, null, ex);
redirectPage = "dataverse.xhtml&alias=" + dataverseService.findRootDataverse().getAlias();
}
logger.log(Level.FINE, "Sending user to = {0}", redirectPage);
return redirectPage + (!redirectPage.contains("?") ? "?" : "&") + "faces-redirect=true";
} catch (AuthenticationFailedException ex) {
AuthenticationResponse response = ex.getResponse();
switch ( response.getStatus() ) {
case FAIL:
JsfHelper.addErrorMessage(BundleUtil.getStringFromBundle("login.builtin.invalidUsernameEmailOrPassword"));
return null;
case ERROR:
/**
* @todo How do we exercise this part of the code? Something
* with password upgrade? See
* https://github.com/IQSS/dataverse/pull/2922
*/
JsfHelper.addErrorMessage(BundleUtil.getStringFromBundle("login.error"));
logger.log( Level.WARNING, "Error logging in: " + response.getMessage(), response.getError() );
return null;
case BREAKOUT:
return response.getMessage();
default:
JsfHelper.addErrorMessage("INTERNAL ERROR");
return null;
}
}
}
public String getCredentialsAuthProviderId() {
return credentialsAuthProviderId;
}
public void resetFilledCredentials( AjaxBehaviorEvent event) {
if ( selectedCredentialsProvider()==null ) return;
filledCredentials = new LinkedList<>();
for ( CredentialsAuthenticationProvider.Credential c : selectedCredentialsProvider().getRequiredCredentials() ) {
filledCredentials.add( new FilledCredential(c, ""));
}
}
public void setCredentialsAuthProviderId(String authProviderId) {
this.credentialsAuthProviderId = authProviderId;
}
public List<FilledCredential> getFilledCredentials() {
return filledCredentials;
}
public void setFilledCredentials(List<FilledCredential> filledCredentials) {
this.filledCredentials = filledCredentials;
}
public boolean isMultipleProvidersAvailable() {
return authSvc.getAuthenticationProviderIds().size()>1;
}
public String getRedirectPage() {
return redirectPage;
}
public void setRedirectPage(String redirectPage) {
this.redirectPage = redirectPage;
}
}