001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.io.auth;
003
004import java.awt.Component;
005import java.net.Authenticator.RequestorType;
006import java.net.PasswordAuthentication;
007import java.util.Objects;
008
009import org.openstreetmap.josm.data.oauth.OAuthToken;
010import org.openstreetmap.josm.gui.JosmUserIdentityManager;
011import org.openstreetmap.josm.io.OsmApi;
012import org.openstreetmap.josm.tools.CheckParameterUtil;
013
014/**
015 * CredentialManager is a factory for the single credential agent used.
016 *
017 * Currently, it defaults to replying an instance of {@link JosmPreferencesCredentialAgent}.
018 * @since 2641
019 */
020public class CredentialsManager implements CredentialsAgent {
021
022    private static volatile CredentialsManager instance;
023
024    /**
025     * Replies the single credential agent used in JOSM
026     *
027     * @return the single credential agent used in JOSM
028     */
029    public static CredentialsManager getInstance() {
030        if (instance == null) {
031            CredentialsAgent delegate;
032            if (agentFactory == null) {
033                delegate = new JosmPreferencesCredentialAgent();
034            } else {
035                delegate = agentFactory.getCredentialsAgent();
036            }
037            instance = new CredentialsManager(delegate);
038        }
039        return instance;
040    }
041
042    private static CredentialsAgentFactory agentFactory;
043
044    public interface CredentialsAgentFactory {
045        CredentialsAgent getCredentialsAgent();
046    }
047
048    /**
049     * Plugins can register a CredentialsAgentFactory, thereby overriding
050     * JOSM's default credentials agent.
051     * @param agentFactory The Factory that provides the custom CredentialsAgent.
052     * Can be null to clear the factory and switch back to default behavior.
053     */
054    public static void registerCredentialsAgentFactory(CredentialsAgentFactory agentFactory) {
055        CredentialsManager.agentFactory = agentFactory;
056        CredentialsManager.instance = null;
057    }
058
059    /* non-static fields and methods */
060
061    /**
062     * The credentials agent doing the real stuff
063     */
064    private CredentialsAgent delegate;
065
066    /**
067     * Constructs a new {@code CredentialsManager}.
068     * @param delegate The credentials agent backing this credential manager. Must not be {@code null}
069     */
070    public CredentialsManager(CredentialsAgent delegate) {
071        CheckParameterUtil.ensureParameterNotNull(delegate, "delegate");
072        this.delegate = delegate;
073    }
074
075    /**
076     * Returns type of credentials agent backing this credentials manager.
077     * @return The type of credentials agent
078     */
079    public final Class<? extends CredentialsAgent> getCredentialsAgentClass() {
080        return delegate.getClass();
081    }
082
083    /**
084     * Returns the username for OSM API
085     * @return the username for OSM API
086     */
087    public String getUsername() {
088        return getUsername(OsmApi.getOsmApi().getHost());
089    }
090
091    /**
092     * Returns the username for a given host
093     * @param host The host for which username is wanted
094     * @return The username for {@code host}
095     */
096    public String getUsername(String host) {
097        String username = null;
098        try {
099            PasswordAuthentication auth = lookup(RequestorType.SERVER, host);
100            if (auth != null) {
101                username = auth.getUserName();
102            }
103        } catch (CredentialsAgentException ex) {
104            return null;
105        }
106        if (username == null) return null;
107        username = username.trim();
108        return username.isEmpty() ? null : username;
109    }
110
111    @Override
112    public PasswordAuthentication lookup(RequestorType requestorType, String host) throws CredentialsAgentException {
113        return delegate.lookup(requestorType, host);
114    }
115
116    @Override
117    public void store(RequestorType requestorType, String host, PasswordAuthentication credentials) throws CredentialsAgentException {
118        if (requestorType == RequestorType.SERVER && Objects.equals(OsmApi.getOsmApi().getHost(), host)) {
119            String username = credentials.getUserName();
120            if (username != null && !username.trim().isEmpty()) {
121                JosmUserIdentityManager.getInstance().setPartiallyIdentified(username);
122            }
123        }
124        delegate.store(requestorType, host, credentials);
125    }
126
127    @Override
128    public CredentialsAgentResponse getCredentials(RequestorType requestorType, String host, boolean noSuccessWithLastResponse)
129            throws CredentialsAgentException {
130        return delegate.getCredentials(requestorType, host, noSuccessWithLastResponse);
131    }
132
133    @Override
134    public OAuthToken lookupOAuthAccessToken() throws CredentialsAgentException {
135        return delegate.lookupOAuthAccessToken();
136    }
137
138    @Override
139    public void storeOAuthAccessToken(OAuthToken accessToken) throws CredentialsAgentException {
140        delegate.storeOAuthAccessToken(accessToken);
141    }
142
143    @Override
144    public Component getPreferencesDecorationPanel() {
145        return delegate.getPreferencesDecorationPanel();
146    }
147}