source: josm/trunk/src/org/openstreetmap/josm/io/auth/AbstractCredentialsAgent.java@ 13274

Last change on this file since 13274 was 12992, checked in by Don-vip, 7 years ago

fix #15435 - do not cache incorrect login credentials when using basic auth

  • Property svn:eol-style set to native
File size: 5.2 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.auth;
3
4import java.net.Authenticator.RequestorType;
5import java.net.PasswordAuthentication;
6import java.util.EnumMap;
7import java.util.Map;
8import java.util.Objects;
9
10import org.openstreetmap.josm.tools.Logging;
11
12/**
13 * Partial implementation of the {@link CredentialsAgent} interface.
14 * <p>
15 * Provides a memory cache for the credentials and means to query the information from the user.
16 * @since 4246
17 */
18public abstract class AbstractCredentialsAgent implements CredentialsAgent {
19
20 /**
21 * Synchronous credentials provider. Called if no credentials are cached. Can be used for user login prompt.
22 * @since 12821
23 */
24 @FunctionalInterface
25 public interface CredentialsProvider {
26 /**
27 * Fills the given response with appropriate user credentials.
28 * @param requestorType type of the entity requesting authentication
29 * @param agent the credentials agent requesting credentials
30 * @param response authentication response to fill
31 * @param username the known username, if any. Likely to be empty
32 * @param password the known password, if any. Likely to be empty
33 * @param host the host against authentication will be performed
34 */
35 void provideCredentials(RequestorType requestorType, AbstractCredentialsAgent agent, CredentialsAgentResponse response,
36 String username, String password, String host);
37 }
38
39 private static volatile CredentialsProvider credentialsProvider =
40 (a, b, c, d, e, f) -> Logging.error("Credentials provider has not been set");
41
42 /**
43 * Sets the global credentials provider.
44 * @param provider credentials provider. Called if no credentials are cached. Can be used for user login prompt
45 */
46 public static void setCredentialsProvider(CredentialsProvider provider) {
47 credentialsProvider = Objects.requireNonNull(provider, "provider");
48 }
49
50 protected Map<RequestorType, PasswordAuthentication> memoryCredentialsCache = new EnumMap<>(RequestorType.class);
51
52 @Override
53 public CredentialsAgentResponse getCredentials(final RequestorType requestorType, final String host, boolean noSuccessWithLastResponse)
54 throws CredentialsAgentException {
55 if (requestorType == null)
56 return null;
57 PasswordAuthentication credentials = lookup(requestorType, host);
58 final String username = (credentials == null || credentials.getUserName() == null) ? "" : credentials.getUserName();
59 final String password = (credentials == null || credentials.getPassword() == null) ? "" : String.valueOf(credentials.getPassword());
60
61 final CredentialsAgentResponse response = new CredentialsAgentResponse();
62
63 /*
64 * Last request was successful and there was no credentials stored in file (or only the username is stored).
65 * -> Try to recall credentials that have been entered manually in this session.
66 */
67 if (!noSuccessWithLastResponse && memoryCredentialsCache.containsKey(requestorType) &&
68 (credentials == null || credentials.getPassword() == null || credentials.getPassword().length == 0)) {
69 PasswordAuthentication pa = memoryCredentialsCache.get(requestorType);
70 response.setUsername(pa.getUserName());
71 response.setPassword(pa.getPassword());
72 response.setCanceled(false);
73 /*
74 * Prompt the user for credentials. This happens the first time each
75 * josm start if the user does not save the credentials to preference
76 * file (username=="") and each time after authentication failed
77 * (noSuccessWithLastResponse == true).
78 */
79 } else if (noSuccessWithLastResponse || username.isEmpty() || password.isEmpty()) {
80 credentialsProvider.provideCredentials(requestorType, this, response, username, password, host);
81 if (response.isCanceled() || response.getUsername() == null || response.getPassword() == null) {
82 return response;
83 }
84 if (response.isSaveCredentials()) {
85 store(requestorType, host, new PasswordAuthentication(
86 response.getUsername(),
87 response.getPassword()
88 ));
89 } else {
90 // User decides not to save credentials to file. Keep it in memory so we don't have to ask over and over again.
91 memoryCredentialsCache.put(requestorType, new PasswordAuthentication(response.getUsername(), response.getPassword()));
92 }
93 } else {
94 // We got it from file.
95 response.setUsername(username);
96 response.setPassword(password.toCharArray());
97 response.setCanceled(false);
98 }
99 return response;
100 }
101
102 @Override
103 public final void purgeCredentialsCache(RequestorType requestorType) {
104 memoryCredentialsCache.remove(requestorType);
105 }
106
107 /**
108 * Provide the text for a checkbox that offers to save the
109 * username and password that has been entered by the user.
110 * @return checkbox text
111 */
112 public abstract String getSaveUsernameAndPasswordCheckboxText();
113}
Note: See TracBrowser for help on using the repository browser.