001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io.auth;
003
004import java.net.Authenticator.RequestorType;
005import java.net.PasswordAuthentication;
006import java.util.HashMap;
007import java.util.Map;
008
009import org.openstreetmap.josm.gui.io.CredentialDialog;
010import org.openstreetmap.josm.gui.util.GuiHelper;
011
012abstract public class AbstractCredentialsAgent implements CredentialsAgent {
013
014    protected Map<RequestorType, PasswordAuthentication> memoryCredentialsCache = new HashMap<RequestorType, PasswordAuthentication>();
015
016    /**
017     * @see CredentialsAgent#getCredentials
018     */
019    @Override
020    public CredentialsAgentResponse getCredentials(final RequestorType requestorType, final String host, boolean noSuccessWithLastResponse) throws CredentialsAgentException{
021        if (requestorType == null)
022            return null;
023        PasswordAuthentication credentials =  lookup(requestorType, host);
024        final String username = (credentials == null || credentials.getUserName() == null) ? "" : credentials.getUserName();
025        final String password = (credentials == null || credentials.getPassword() == null) ? "" : String.valueOf(credentials.getPassword());
026
027        final CredentialsAgentResponse response = new CredentialsAgentResponse();
028
029        /*
030         * Last request was successful and there was no credentials stored
031         * in file (or only the username is stored).
032         * -> Try to recall credentials that have been entered
033         * manually in this session.
034         */
035        if (!noSuccessWithLastResponse && memoryCredentialsCache.containsKey(requestorType) &&
036                (credentials == null || credentials.getPassword() == null || credentials.getPassword().length == 0)) {
037            PasswordAuthentication pa = memoryCredentialsCache.get(requestorType);
038            response.setUsername(pa.getUserName());
039            response.setPassword(pa.getPassword());
040            response.setCanceled(false);
041        /*
042         * Prompt the user for credentials. This happens the first time each
043         * josm start if the user does not save the credentials to preference
044         * file (username=="") and each time after authentication failed
045         * (noSuccessWithLastResponse == true).
046         */
047        } else if (noSuccessWithLastResponse || username.isEmpty() || password.isEmpty()) {
048            GuiHelper.runInEDTAndWait(new Runnable() {
049                @Override
050                public void run() {
051                    CredentialDialog dialog = null;
052                    if (requestorType.equals(RequestorType.PROXY))
053                        dialog = CredentialDialog.getHttpProxyCredentialDialog(username, password, host, getSaveUsernameAndPasswordCheckboxText());
054                    else
055                        dialog = CredentialDialog.getOsmApiCredentialDialog(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()) {
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     */
096    public abstract String getSaveUsernameAndPasswordCheckboxText();
097}