summaryrefslogblamecommitdiffstats
path: root/dozentenmodul/src/main/java/org/openslx/dozmod/gui/window/LoginWindow.java
blob: d089fafdfa6840828a8a087ca823cfea05909f4b (plain) (tree)
1
2
3
4
5
6
7
8
9
10
                                      
 
                      

                                     

                                   
                               

                                    
                    


                          
                                  
                                        
                              
                          
                             
                                  
 
                               
                                     
                                    
                                                  
                                               


                                                       
                                                                          

                                                                             
                                                            


                                                                  
                                         
                                                   
                                                 
                                                        
                                                              
                                         
                                               
                                             
                                                         

                                                       



                                                          
 

                         
   
   
                           
                                                    
 
                                                                                 
 
                                      





                                    
                                                 




                                                          
                                             
                         

                                                                          
 
                                                     
 
                                               
                                                         
                                   






                                                                     
                                               
                                                                 

                                                                                  


                                                                                       
                                                                                                                                               
                                                                 
                                                                                                      
                                         


                                 
 

                                                                          
                                         
                     
                                                                            

                                                                                         
                                                       
                 
 
                                                      
                                                                        
                                           
                 
                                         
                                                  
                                               
                                                                            
                                                  
                                                                  











                                                                          
                                                                                    




                                                                                  
                                                                                                                       

                                                                  





                                                                                     
                                                                  



                                         
 
                                                                 

                                                                    


                                                                                                                   


                                          



                                                                            
                                                                                    

                         

                                                
                                                                                            
                                                                                       
                                                                               
                                 
                                                                     
                                                   
                         
                   
 





                                                                    



                                                                    
                                                                                         

                         






                                                                                                         
 
                                                                                        

                                               
                                                                                                           
                                               
                                                                    


                                                           
                                                                                        




                                                                                           
                                                                              


                                                              

                                                                                                                        



                                         




                                                                             
                                                                    

                                                               
 




                                                                                  
 
                                                                                                                              

                                                                          

                                                                                                                    







                                                                               
                                                   
                                        
                                                                








                                                                                              
                                                                                                         













                                                                                   

                                                                                                                    

                               
                                                                                             

                                                                                                                
                                                               

                               
                                                    

                                                                                      










                                                                                               
                                                                                                         
 


                                                                     

                                            
                                                                                                 
                                 
                                                                                                                  

                                                     






                                                                                  





                                                                                                             

                                                                                                                             

                                                        
                                                                             
                                                                                                            

                                                       

                                                                                                                                 


                                                   


                                                                                                                      
                                                                                                                      


                                                                                                                 

                                              
                                                  

                         

                                                   
                                                  














                                                                                                             
                                   



                                                      

                                                  

                                                                                                            
                                               





                                                                                                                           
                                                  

                         
         
 

                                                                      

                      
           

                                                                                               

                                                      
                                                                     
                                                                                                                    
                                                           

                                                                                                                     
                         

                                  
                 

                                  
 
                                                  





                                                   



                                                                                


                                                                   
                                
                                                                   

                         

         


















                                                                                                           









                                                     


                                 
                                                    
 
                                                               
                                     
         
 
package org.openslx.dozmod.gui.window;

import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.Iterator;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import org.apache.log4j.Logger;
import org.apache.thrift.TBaseHelper;
import org.apache.thrift.TException;
import org.openslx.bwlp.thrift.iface.Organization;
import org.openslx.bwlp.thrift.iface.Satellite;
import org.openslx.dozmod.App;
import org.openslx.dozmod.Config;
import org.openslx.dozmod.authentication.Authenticator;
import org.openslx.dozmod.authentication.Authenticator.AuthenticationData;
import org.openslx.dozmod.authentication.Authenticator.AuthenticatorCallback;
import org.openslx.dozmod.authentication.EcpAuthenticator;
import org.openslx.dozmod.authentication.FingerprintManager;
import org.openslx.dozmod.authentication.ShibbolethEcp.ReturnCode;
import org.openslx.dozmod.authentication.TestAccountAuthenticator;
import org.openslx.dozmod.gui.Gui;
import org.openslx.dozmod.gui.MainWindow;
import org.openslx.dozmod.gui.activity.UpdatePanel;
import org.openslx.dozmod.gui.helper.MessageType;
import org.openslx.dozmod.gui.helper.TextChangeListener;
import org.openslx.dozmod.gui.window.layout.LoginWindowLayout;
import org.openslx.dozmod.thrift.Session;
import org.openslx.dozmod.thrift.ThriftActions;
import org.openslx.dozmod.thrift.ThriftError;
import org.openslx.dozmod.thrift.cache.OrganizationCache;
import org.openslx.dozmod.util.DesktopEnvironment;
import org.openslx.dozmod.util.DesktopEnvironment.Link;
import org.openslx.util.QuickTimer;
import org.openslx.util.QuickTimer.Task;

import edu.kit.scc.dei.ecplean.ECPAuthenticationException;

/**
 * @author Jonathan Bauer
 * 
 */
@SuppressWarnings("serial")
public class LoginWindow extends LoginWindowLayout {

	private final static Logger LOGGER = Logger.getLogger(LoginWindow.class);

	public static enum LoginType {
		ECP(0),
		TEST_ACCOUNT(1),
		DIRECT_CONNECT(2);

		public final int id;

		private LoginType(final int id) {
			this.id = id;
		}
	}

	// authentication method to use for login attempts
	protected LoginType loginType = null;
	// text constants
	private final String NO_USERNAME = "Kein Benutzername angegeben!";
	private final String NO_PASSWORD = "Kein Passwort angegeben!";

	private boolean forceCustomSatellite = false;

	public LoginWindow(Frame modalParent) {
		// call the constructor of the superclass
		super(modalParent);
		setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
		addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				Gui.exit(0);
			}
		});
		// first do all listeners stuff
		for (final LoginType type : LoginType.values()) {
			rdoLoginType[type.id].setActionCommand(type.toString());
			rdoLoginType[type.id].addItemListener(new ItemListener() {
				@Override
				public void itemStateChanged(ItemEvent e) {
					if (e.getStateChange() == ItemEvent.SELECTED) {
						cboOrganization.setEnabled(cboOrganization.getModel().getSize() != 0 && type == LoginType.ECP);
						loginType = type;
						btnOpenRegistration.setEnabled(type == LoginType.ECP);
					}
				}
			});
		}

		// check if we had saved an authentication method
		String savedAuthMethod = Config.getAuthenticationMethod();
		LoginType savedLoginType;
		try {
			savedLoginType = LoginType.valueOf(savedAuthMethod);
		} catch (Exception e) {
			// if no valid LOGIN_TYPE was saved, just enable the BWIDM button
			savedLoginType = LoginType.ECP;
		}

		if (savedLoginType == LoginType.ECP) {
			// disable login button til the idp list is here
			enableLogin(false);
		}
		// While filling, disable
		cboOrganization.setEnabled(false);
		// Not yet implemented, disable
		rdoLoginType[LoginType.DIRECT_CONNECT.id].setEnabled(false);
		// enable the corresponding button
		rdoLoginType[savedLoginType.id].setSelected(true);
		loginType = savedLoginType;

		QuickTimer.scheduleOnce(new Task() {
			List<Organization> orgs = null;

			@Override
			public void fire() {
				try {
					// Wait for proxy server init
					App.waitForInit();
					orgs = OrganizationCache.getAll();
				} catch (Exception e) {
					LOGGER.error("Error during execution: ", e);
				}
				// filter out every organisation without ecp
				Iterator<Organization> iterator = orgs.iterator();
				while (iterator.hasNext()) {
					Organization current = iterator.next();
					if (current == null || !current.isSetEcpUrl() || current.getEcpUrl().isEmpty())
						iterator.remove();
				}
				// now send the organisations back to the LoginWindow
				// through populateIdpCombo()
				Gui.asyncExec(new Runnable() {
					@Override
					public void run() {
						populateIdpCombo(orgs);
						enableLogin(true);
					}
				});
			}
		});

		btnLogin.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				int mods = e.getModifiers();
				// evaluate if SHIFT was hold during the click
				forceCustomSatellite = ((mods & ActionEvent.SHIFT_MASK) == ActionEvent.SHIFT_MASK);
				doLogin();
			}
		});
		
		btnOpenRegistration.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				DesktopEnvironment.openWebpage(Link.REGISTER_BWIDM);
			}
		});

		// make enter key activate login
		pnlLoginForm.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
				KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "login");
		pnlLoginForm.getActionMap().put("login", new AbstractAction() {
			@Override
			public void actionPerformed(ActionEvent ae) {
				btnLogin.doClick();
			}
		});

		btnSettings.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				ConfigWindow.open(LoginWindow.this);
			}
		});
		
		btnLogDir.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				DesktopEnvironment.openLocal(new File(Config.getPath()));
			}
		});
		
		btnUpdateCheck.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				CheckUpdateWindow.open(SwingUtilities.getWindowAncestor(btnUpdateCheck));
			}
		});

		txtUsername.getDocument().addDocumentListener(new TextChangeListener() {
			@Override
			public void changed() {
				if (cboOrganization.getSelectedIndex() != -1 || loginType != LoginType.ECP)
					return;
				String name = txtUsername.getText();
				int at = name.indexOf('@');
				if (at == -1)
					return;
				final int oldCursorPos = txtUsername.getCaretPosition();
				String suffix = name.substring(at + 1);
				Organization organization = OrganizationCache.find(suffix);
				if (organization == null)
					return;
				final String nameOnly = name.substring(0, at);
				cboOrganization.setSelectedItem(organization);
				Gui.asyncExec(new Runnable() {
					@Override
					public void run() {
						txtUsername.setText(nameOnly);
						txtUsername.setCaretPosition(Math.min(oldCursorPos, nameOnly.length()));
					}
				});
			}
		});
	}

	/**
	 * Called by the thread fetching the organization list from the cache
	 * 
	 * @param orgs list of organization to show in the combo box
	 */
	public void populateIdpCombo(List<Organization> orgs) {

		// sanity checks on orgs
		if (orgs == null) {
			LOGGER.error("No organizations received from the cache.");
			return;
		}

		cboOrganization.setModel(new DefaultComboBoxModel<Organization>(orgs.toArray(new Organization[orgs.size()])));
		// now check if we had a saved identity provider
		String savedOrganizationId = Config.getIdentityProvider();
		cboOrganization.setSelectedItem(OrganizationCache.find(savedOrganizationId));
		cboOrganization.setEnabled(cboOrganization.getModel().getSize() != 0 && loginType == LoginType.ECP);
	}

	/**
	 * Saves various user choices to the config file.
	 * This gets triggered when the login button is activated.
	 */
	private void doSaveConfig() {
		// first we need to check if the "Remember me" button is active
		if (chkSaveUsername.isSelected()) {
			// save username
			String username = txtUsername.getText();
			if (!username.isEmpty()) {
				Config.setUsername(username);
			}
		} else {
			Config.setUsername("");
		}
		// always save the authentication method and potentially the identity provider
		Config.setAuthenticationMethod(loginType.toString());
		// save the selected identity provider
		Organization selectedOrg = cboOrganization.getItemAt(cboOrganization.getSelectedIndex());
		if (selectedOrg != null) {
			Config.setIdentityProvider(selectedOrg.organizationId);
		}
	}

	/**
	 * Actually do the login using the username/password in the field using the
	 * authentication mechanism corresponding to the selected authButton
	 * 
	 * @throws ECPAuthenticationException
	 */
	private void doLogin() {
		// sanity check on loginType.
		if (loginType == null) {
			Gui.showMessageBox(this, "Bitte wählen Sie eine Authentifizierungsart.", MessageType.ERROR,
					LOGGER, null);
			return;
		}
		if (loginType == LoginType.ECP && cboOrganization.getSelectedIndex() == -1) {
			Gui.showMessageBox(this, "Bitte wählen Sie ihre Organisation als 'Identity Provider'.",
					MessageType.ERROR, LOGGER, null);
			cboOrganization.requestFocusInWindow();
			return;
		}
		// here we only check for the fields
		String username = txtUsername.getText();
		final String password = String.copyValueOf(txtPassword.getPassword());
		// login clicked, lets first read the fields
		if (username.isEmpty()) {
			Gui.showMessageBox(this, NO_USERNAME, MessageType.ERROR, LOGGER, null);
			return;
		}
		if (password.isEmpty()) {
			Gui.showMessageBox(this, NO_PASSWORD, MessageType.ERROR, LOGGER, null);
			return;
		}

		// determine which organization was selected by the user.
		Organization selectedOrg = cboOrganization.getItemAt(cboOrganization.getSelectedIndex());

		// we are doing the login soon, first save the config
		doSaveConfig();

		// Setup login callback
		final LoginWindow me = this;
		final AuthenticatorCallback authenticatorCallback = new AuthenticatorCallback() {
			@Override
			public void postLogin(ReturnCode returnCode, final AuthenticationData data, Throwable t) {
				switch (returnCode) {
				case NO_ERROR:
					Gui.asyncExec(new Runnable() {
						@Override
						public void run() {
							postSuccessfulLogin(data);
						}
					});
					return;
				case IDENTITY_PROVIDER_ERROR:
					Gui.showMessageBox(me, "IdP Error", MessageType.ERROR, LOGGER, null);
					break;
				case SERVICE_PROVIDER_ERROR:
					// here if we have t != null then we have not received a token
					// if we have t, then the token is invalid.
					Gui.showMessageBox(me, "Invalid token from the service provider!", MessageType.ERROR,
							LOGGER, t);
					break;
				case UNREGISTERED_ERROR:
					LOGGER.error("User not registered!");
					BwIdmLinkWindow.open((JFrame) SwingUtilities.getWindowAncestor(me));
					break;
				case INVALID_URL_ERROR:
					Gui.showMessageBox(me, "ECP Authenticator says: Invalid URL.", MessageType.ERROR, LOGGER,
							t);
					break;
				case GENERIC_ERROR:
				default:
					if (t == null || !t.getClass().equals(RuntimeException.class)) {
						Gui.showMessageBox(me, "Internal error!", MessageType.ERROR, null, t);
					} else {
						Gui.showMessageBox(me, "Der Masterserver hat den Loginversuch mit der"
								+ " folgenden Nachricht abgewiesen:\n\n"
								+ t.getMessage(), MessageType.ERROR, null, null);
					}
					break;
				}
				enableLogin(true);
			}
		};

		// now switch over the login types.
		final Authenticator authenticator;
		switch (loginType) {
		case ECP:
			authenticator = new EcpAuthenticator(selectedOrg.getEcpUrl());
			break;
		case TEST_ACCOUNT:
			authenticator = new TestAccountAuthenticator();
			break;
		case DIRECT_CONNECT:
			Gui.showMessageBox(this, "Not yet implemented", MessageType.ERROR, LOGGER, null);
			return;
		default:
			Gui.showMessageBox(this, "No login type selected!", MessageType.ERROR, LOGGER, null);
			return;
		}

		enableLogin(false);
		final String finalUsername = username;
		QuickTimer.scheduleOnce(new Task() {
			@Override
			public void fire() {
				// Execute login
				App.waitForInit();
				try {
					authenticator.login(finalUsername, password, authenticatorCallback);
					return;
				} catch (TException e) {
					ThriftError.showMessage(LoginWindow.this, LOGGER, e, "Anmeldung fehlgeschlagen");
				} catch (Exception e) {
					Gui.showMessageBox(LoginWindow.this, "Anmeldung fehlgeschlagen", MessageType.ERROR,
							LOGGER, e);
				}
				enableLogin(true);
			}
		});
	}

	/**
	 * Functions called by doLogin is the login process succeeded.
	 * 
	 * @param data
	 */
	private void postSuccessfulLogin(AuthenticationData data) {
		LOGGER.info(loginType.toString() + " succeeded, token " + data.satelliteToken);
		// Update known suggested fingerprints
		importFingerprints(data.satellites);
		// now try to init the session with the data received
		if (ThriftActions.initSession(data, forceCustomSatellite, SwingUtilities.getWindowAncestor(this))) {
			if (chkSaveUsername.isSelected()) {
				Config.saveCurrentSession(Session.getSatelliteAddress(), Session.getSatelliteToken(),
						Session.getMasterToken());
			}
			dispose();
			return;
		}
		enableLogin(true);
	}

	private void enableLogin(boolean enable) {
		btnLogin.setEnabled(enable);
		txtUsername.setEnabled(enable);
		txtPassword.setEnabled(enable);
		pnlLoginType.setEnabled(enable);
		pnlLoginForm.setEnabled(enable);
		chkSaveUsername.setEnabled(enable);
		if (enable) {
			// Do this here, otherwise the focus might not be set
			String savedUsername = Config.getUsername();
			if (savedUsername != null && !savedUsername.isEmpty()) {
				txtUsername.setText(savedUsername);
				chkSaveUsername.setSelected(true);
				txtPassword.requestFocusInWindow();
			} else {
				txtUsername.requestFocusInWindow();
			}
		}
	}

	/**
	 * If master server supplies certificate finger prints for a satellite,
	 * store them so we can verify later.
	 * 
	 * @param satellites
	 */
	private void importFingerprints(List<Satellite> satellites) {
		if (satellites == null || satellites.isEmpty())
			return;
		for (Satellite sat : satellites) {
			if (sat.addressList == null || sat.certSha256 == null || sat.addressList.isEmpty())
				continue;
			byte[] fingerprint = TBaseHelper.byteBufferToByteArray(sat.certSha256);
			for (String address : sat.addressList) {
				FingerprintManager.saveSuggestedFingerprint(address, fingerprint);
			}
		}
	}

	@SuppressWarnings("deprecation")
	@Override
	public void show() {
		if (!isVisible()) {
			pack();
			MainWindow.centerShell(this);
		}
		super.show();
	}

	/**
	 * Opens the login window
	 */
	public static void open(Frame modalParent) {

		LoginWindow win = new LoginWindow(modalParent);
		win.setVisible(true);
	}
}