001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.io.auth; 003 004import java.awt.GraphicsEnvironment; 005import java.net.Authenticator.RequestorType; 006import java.net.PasswordAuthentication; 007import java.util.EnumMap; 008import java.util.Map; 009 010import org.openstreetmap.josm.gui.io.CredentialDialog; 011import org.openstreetmap.josm.gui.util.GuiHelper; 012 013public abstract class AbstractCredentialsAgent implements CredentialsAgent { 014 015 protected Map<RequestorType, PasswordAuthentication> memoryCredentialsCache = new EnumMap<>(RequestorType.class); 016 017 @Override 018 public CredentialsAgentResponse getCredentials(final RequestorType requestorType, final String host, boolean noSuccessWithLastResponse) 019 throws CredentialsAgentException { 020 if (requestorType == null) 021 return null; 022 PasswordAuthentication credentials = lookup(requestorType, host); 023 final String username = (credentials == null || credentials.getUserName() == null) ? "" : credentials.getUserName(); 024 final String password = (credentials == null || credentials.getPassword() == null) ? "" : String.valueOf(credentials.getPassword()); 025 026 final CredentialsAgentResponse response = new CredentialsAgentResponse(); 027 028 /* 029 * Last request was successful and there was no credentials stored 030 * in file (or only the username is stored). 031 * -> Try to recall credentials that have been entered 032 * manually in this session. 033 */ 034 if (!noSuccessWithLastResponse && memoryCredentialsCache.containsKey(requestorType) && 035 (credentials == null || credentials.getPassword() == null || credentials.getPassword().length == 0)) { 036 PasswordAuthentication pa = memoryCredentialsCache.get(requestorType); 037 response.setUsername(pa.getUserName()); 038 response.setPassword(pa.getPassword()); 039 response.setCanceled(false); 040 /* 041 * Prompt the user for credentials. This happens the first time each 042 * josm start if the user does not save the credentials to preference 043 * file (username=="") and each time after authentication failed 044 * (noSuccessWithLastResponse == true). 045 */ 046 } else if (noSuccessWithLastResponse || username.isEmpty() || password.isEmpty()) { 047 if (!GraphicsEnvironment.isHeadless()) { 048 GuiHelper.runInEDTAndWait(() -> { 049 CredentialDialog dialog; 050 if (requestorType.equals(RequestorType.PROXY)) 051 dialog = CredentialDialog.getHttpProxyCredentialDialog( 052 username, password, host, getSaveUsernameAndPasswordCheckboxText()); 053 else 054 dialog = CredentialDialog.getOsmApiCredentialDialog( 055 username, password, host, getSaveUsernameAndPasswordCheckboxText()); 056 dialog.setVisible(true); 057 response.setCanceled(dialog.isCanceled()); 058 if (dialog.isCanceled()) 059 return; 060 response.setUsername(dialog.getUsername()); 061 response.setPassword(dialog.getPassword()); 062 response.setSaveCredentials(dialog.isSaveCredentials()); 063 }); 064 } 065 if (response.isCanceled() || response.getUsername() == null || response.getPassword() == null) { 066 return response; 067 } 068 if (response.isSaveCredentials()) { 069 store(requestorType, host, new PasswordAuthentication( 070 response.getUsername(), 071 response.getPassword() 072 )); 073 /* 074 * User decides not to save credentials to file. Keep it 075 * in memory so we don't have to ask over and over again. 076 */ 077 } else { 078 PasswordAuthentication pa = new PasswordAuthentication(response.getUsername(), response.getPassword()); 079 memoryCredentialsCache.put(requestorType, pa); 080 } 081 /* 082 * We got it from file. 083 */ 084 } else { 085 response.setUsername(username); 086 response.setPassword(password.toCharArray()); 087 response.setCanceled(false); 088 } 089 return response; 090 } 091 092 /** 093 * Provide the text for a checkbox that offers to save the 094 * username and password that has been entered by the user. 095 * @return checkbox text 096 */ 097 public abstract String getSaveUsernameAndPasswordCheckboxText(); 098}