001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io.auth;
003
004import java.net.Authenticator;
005import java.net.PasswordAuthentication;
006import java.util.EnumMap;
007import java.util.Map;
008import java.util.Objects;
009
010import org.openstreetmap.josm.Main;
011import org.openstreetmap.josm.io.OsmApi;
012
013/**
014 * This is the default authenticator used in JOSM. It delegates lookup of credentials
015 * for the OSM API and an optional proxy server to the currently configured {@link CredentialsManager}.
016 * @since 2641
017 */
018public final class DefaultAuthenticator extends Authenticator {
019    private static volatile DefaultAuthenticator instance;
020
021    /**
022     * Returns the unique instance
023     * @return The unique instance
024     */
025    public static DefaultAuthenticator getInstance() {
026        return instance;
027    }
028
029    /**
030     * Creates the unique instance
031     */
032    public static void createInstance() {
033        instance = new DefaultAuthenticator();
034    }
035
036    private final Map<RequestorType, Boolean> credentialsTried = new EnumMap<>(RequestorType.class);
037    private boolean enabled = true;
038
039    private DefaultAuthenticator() {
040    }
041
042    /**
043     * Called by the Java HTTP stack when either the OSM API server or a proxy requires authentication.
044     */
045    @Override
046    protected PasswordAuthentication getPasswordAuthentication() {
047        if (!enabled)
048            return null;
049        try {
050            if (OsmApi.isUsingOAuth()
051                    && Objects.equals(OsmApi.getOsmApi().getHost(), getRequestingHost())
052                    && RequestorType.SERVER.equals(getRequestorType())) {
053                // if we are working with OAuth we don't prompt for a password
054                return null;
055            }
056            boolean tried = credentialsTried.get(getRequestorType()) != null;
057            CredentialsAgentResponse response = CredentialsManager.getInstance().getCredentials(getRequestorType(), getRequestingHost(), tried);
058            if (response == null || response.isCanceled())
059                return null;
060            credentialsTried.put(getRequestorType(), Boolean.TRUE);
061            return new PasswordAuthentication(response.getUsername(), response.getPassword());
062        } catch (CredentialsAgentException e) {
063            Main.error(e);
064            return null;
065        }
066    }
067
068    public boolean isEnabled() {
069        return enabled;
070    }
071
072    public void setEnabled(boolean enabled) {
073        this.enabled = enabled;
074    }
075}