Changeset 18991 in josm for trunk/src


Ignore:
Timestamp:
2024-02-21T21:26:18+01:00 (9 months ago)
Author:
taylor.smock
Message:

Fix #22810: OSM OAuth 1.0a/Basic auth deprecation and removal

As of 2024-02-15, something changed in the OSM server configuration. This broke
our OAuth 1.0a implementation (see #23475). As such, we are removing OAuth 1.0a
from JOSM now instead of when the OSM server removes support in June 2024.

For third-party OpenStreetMap servers, the Basic Authentication method has been
kept. However, they should be made aware that it may be removed if a non-trivial
bug occurs with it. We highly recommend that the third-party servers update to
the current OpenStreetMap website implementation (if only for their own security).

Failing that, the third-party server can implement RFC8414. As of this commit,
we currently use the authorization_endpoint and token_endpoint fields.
To check and see if their third-party server implements RFC8414, they can go
to <server host>/.well-known/oauth-authorization-server.

Prominent third-party OpenStreetMap servers may give us a client id for their
specific server. That client id may be added to the hard-coded client id list
at maintainer discretion. At a minimum, the server must be publicly
available and have a significant user base.

Location:
trunk/src/org/openstreetmap/josm
Files:
7 deleted
20 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/oauth/OAuth20Parameters.java

    r18723 r18991  
    148148        return builder.build().toString();
    149149    }
     150
     151    @Override
     152    public int hashCode() {
     153        return Objects.hash(this.apiUrl, this.authorizeUrl, this.tokenUrl, this.clientId, this.clientSecret, this.redirectUri);
     154    }
     155
     156    @Override
     157    public boolean equals(Object obj) {
     158        if (obj != null && this.getClass() == obj.getClass()) {
     159            OAuth20Parameters other = (OAuth20Parameters) obj;
     160            return Objects.equals(this.clientSecret, other.clientSecret) &&
     161                    Objects.equals(this.clientId, other.clientId) &&
     162                    Objects.equals(this.redirectUri, other.redirectUri) &&
     163                    Objects.equals(this.tokenUrl, other.tokenUrl) &&
     164                    Objects.equals(this.authorizeUrl, other.authorizeUrl) &&
     165                    Objects.equals(this.apiUrl, other.apiUrl);
     166        }
     167        return false;
     168    }
    150169}
  • trunk/src/org/openstreetmap/josm/data/oauth/OAuthAccessTokenHolder.java

    r18764 r18991  
    3737
    3838    private boolean saveToPreferences;
    39     private String accessTokenKey;
    40     private String accessTokenSecret;
    4139
    4240    private final Map<String, Map<OAuthVersion, IOAuthToken>> tokenMap = new HashMap<>();
     
    5351    /**
    5452     * Sets whether the current access token should be saved to the preferences file.
    55      *
     53     * <p>
    5654     * If true, the access token is saved in clear text to the preferences file. The same
    5755     * access token can therefore be used in multiple JOSM sessions.
    58      *
     56     * <p>
    5957     * If false, the access token isn't saved to the preferences file. If JOSM is closed,
    6058     * the access token is lost and new token has to be generated by the OSM server the
     
    6563    public void setSaveToPreferences(boolean saveToPreferences) {
    6664        this.saveToPreferences = saveToPreferences;
    67     }
    68 
    69     /**
    70      * Replies the access token key. null, if no access token key is currently set.
    71      *
    72      * @return the access token key
    73      */
    74     public String getAccessTokenKey() {
    75         return accessTokenKey;
    76     }
    77 
    78     /**
    79      * Sets the access token key. Pass in null to remove the current access token key.
    80      *
    81      * @param accessTokenKey the access token key
    82      */
    83     public void setAccessTokenKey(String accessTokenKey) {
    84         this.accessTokenKey = accessTokenKey;
    85     }
    86 
    87     /**
    88      * Replies the access token secret. null, if no access token secret is currently set.
    89      *
    90      * @return the access token secret
    91      */
    92     public String getAccessTokenSecret() {
    93         return accessTokenSecret;
    94     }
    95 
    96     /**
    97      * Sets the access token secret. Pass in null to remove the current access token secret.
    98      *
    99      * @param accessTokenSecret access token secret, or null
    100      */
    101     public void setAccessTokenSecret(String accessTokenSecret) {
    102         this.accessTokenSecret = accessTokenSecret;
    103     }
    104 
    105     /**
    106      * Replies the access token.
    107      * @return the access token, can be {@code null}
    108      */
    109     public OAuthToken getAccessToken() {
    110         if (!containsAccessToken())
    111             return null;
    112         return new OAuthToken(accessTokenKey, accessTokenSecret);
    11365    }
    11466
     
    14395     * Sets the access token hold by this holder.
    14496     *
    145      * @param accessTokenKey the access token key
    146      * @param accessTokenSecret the access token secret
    147      */
    148     public void setAccessToken(String accessTokenKey, String accessTokenSecret) {
    149         this.accessTokenKey = accessTokenKey;
    150         this.accessTokenSecret = accessTokenSecret;
    151     }
    152 
    153     /**
    154      * Sets the access token hold by this holder.
    155      *
    156      * @param token the access token. Can be null to clear the content in this holder.
    157      */
    158     public void setAccessToken(OAuthToken token) {
    159         if (token == null) {
    160             this.accessTokenKey = null;
    161             this.accessTokenSecret = null;
    162         } else {
    163             this.accessTokenKey = token.getKey();
    164             this.accessTokenSecret = token.getSecret();
    165         }
    166     }
    167 
    168     /**
    169      * Sets the access token hold by this holder.
    170      *
    17197     * @param api The api the token is for
    17298     * @param token the access token. Can be null to clear the content in this holder.
     
    187113
    188114    /**
    189      * Replies true if this holder contains an complete access token, consisting of an
    190      * Access Token Key and an Access Token Secret.
    191      *
    192      * @return true if this holder contains an complete access token
    193      */
    194     public boolean containsAccessToken() {
    195         return accessTokenKey != null && accessTokenSecret != null;
    196     }
    197 
    198     /**
    199115     * Initializes the content of this holder from the Access Token managed by the
    200116     * credential manager.
     
    205121    public void init(CredentialsAgent cm) {
    206122        CheckParameterUtil.ensureParameterNotNull(cm, "cm");
    207         OAuthToken token = null;
    208         try {
    209             token = cm.lookupOAuthAccessToken();
    210         } catch (CredentialsAgentException e) {
    211             Logging.error(e);
    212             Logging.warn(tr("Failed to retrieve OAuth Access Token from credential manager"));
    213             Logging.warn(tr("Current credential manager is of type ''{0}''", cm.getClass().getName()));
    214         }
    215123        saveToPreferences = Config.getPref().getBoolean("oauth.access-token.save-to-preferences", true);
    216         if (token != null) {
    217             accessTokenKey = token.getKey();
    218             accessTokenSecret = token.getSecret();
    219         }
    220124    }
    221125
     
    232136        try {
    233137            if (!saveToPreferences) {
    234                 cm.storeOAuthAccessToken(null);
    235138                for (String host : this.tokenMap.keySet()) {
    236139                    cm.storeOAuthAccessToken(host, null);
    237140                }
    238141            } else {
    239                 if (this.accessTokenKey != null && this.accessTokenSecret != null) {
    240                     cm.storeOAuthAccessToken(new OAuthToken(accessTokenKey, accessTokenSecret));
    241                 } else {
    242                     cm.storeOAuthAccessToken(null);
    243                 }
    244142                for (Map.Entry<String, Map<OAuthVersion, IOAuthToken>> entry : this.tokenMap.entrySet()) {
    245143                    if (entry.getValue().isEmpty()) {
     
    265163     */
    266164    public void clear() {
    267         accessTokenKey = null;
    268         accessTokenSecret = null;
     165        this.tokenMap.clear();
    269166    }
    270167}
  • trunk/src/org/openstreetmap/josm/data/oauth/OAuthParameters.java

    r18723 r18991  
    44import java.io.BufferedReader;
    55import java.io.IOException;
     6import java.net.URI;
     7import java.net.URISyntaxException;
    68import java.net.URL;
    7 import java.util.Objects;
     9import java.util.HashMap;
     10import java.util.Map;
     11
     12import org.openstreetmap.josm.io.NetworkManager;
     13import org.openstreetmap.josm.io.OsmApi;
     14import org.openstreetmap.josm.io.auth.CredentialsAgentException;
     15import org.openstreetmap.josm.io.auth.CredentialsManager;
     16import org.openstreetmap.josm.spi.preferences.Config;
     17import org.openstreetmap.josm.spi.preferences.IUrls;
     18import org.openstreetmap.josm.tools.HttpClient;
     19import org.openstreetmap.josm.tools.JosmRuntimeException;
     20import org.openstreetmap.josm.tools.Logging;
     21import org.openstreetmap.josm.tools.Utils;
    822
    923import jakarta.json.Json;
     
    1327import jakarta.json.JsonValue;
    1428
    15 import org.openstreetmap.josm.io.OsmApi;
    16 import org.openstreetmap.josm.io.auth.CredentialsAgentException;
    17 import org.openstreetmap.josm.io.auth.CredentialsManager;
    18 import org.openstreetmap.josm.spi.preferences.Config;
    19 import org.openstreetmap.josm.spi.preferences.IUrls;
    20 import org.openstreetmap.josm.tools.CheckParameterUtil;
    21 import org.openstreetmap.josm.tools.HttpClient;
    22 import org.openstreetmap.josm.tools.Logging;
    23 import org.openstreetmap.josm.tools.Utils;
    24 
    25 import oauth.signpost.OAuthConsumer;
    26 import oauth.signpost.OAuthProvider;
    27 
    2829/**
    2930 * This class manages an immutable set of OAuth parameters.
    30  * @since 2747
     31 * @since 2747 (static factory class since 18991)
    3132 */
    32 public class OAuthParameters implements IOAuthParameters {
    33 
    34     /**
    35      * The default JOSM OAuth consumer key (created by user josmeditor).
    36      */
    37     public static final String DEFAULT_JOSM_CONSUMER_KEY = "F7zPYlVCqE2BUH9Hr4SsWZSOnrKjpug1EgqkbsSb";
    38     /**
    39      * The default JOSM OAuth consumer secret (created by user josmeditor).
    40      */
    41     public static final String DEFAULT_JOSM_CONSUMER_SECRET = "rIkjpPcBNkMQxrqzcOvOC4RRuYupYr7k8mfP13H5";
     33public final class OAuthParameters {
     34    private static final Map<String, JsonObject> RFC8414_RESPONSES = new HashMap<>(1);
     35    private static final String OSM_API_DEFAULT = "https://api.openstreetmap.org/api";
     36    private static final String OSM_API_DEV = "https://api06.dev.openstreetmap.org/api";
     37    private static final String OSM_API_MASTER = "https://master.apis.dev.openstreetmap.org/api";
     38
     39    private OAuthParameters() {
     40        // Hide constructor
     41    }
    4242
    4343    /**
    4444     * Replies a set of default parameters for a consumer accessing the standard OSM server
    4545     * at {@link IUrls#getDefaultOsmApiUrl}.
    46      *
     46     * <p>
     47     * Note that this may make network requests for RFC 8414 compliant endpoints.
    4748     * @return a set of default parameters
    4849     */
    49     public static OAuthParameters createDefault() {
    50         return createDefault(null);
     50    public static IOAuthParameters createDefault() {
     51        return createDefault(Config.getUrls().getDefaultOsmApiUrl(), OAuthVersion.OAuth20);
    5152    }
    5253
     
    5556     * at the given API url. URL parameters are only set if the URL equals {@link IUrls#getDefaultOsmApiUrl}
    5657     * or references the domain "dev.openstreetmap.org", otherwise they may be <code>null</code>.
    57      *
    58      * @param apiUrl The API URL for which the OAuth default parameters are created. If null or empty, the default OSM API url is used.
    59      * @return a set of default parameters for the given {@code apiUrl}
    60      * @since 5422
    61      */
    62     public static OAuthParameters createDefault(String apiUrl) {
    63         return (OAuthParameters) createDefault(apiUrl, OAuthVersion.OAuth10a);
    64     }
    65 
    66     /**
    67      * Replies a set of default parameters for a consumer accessing an OSM server
    68      * at the given API url. URL parameters are only set if the URL equals {@link IUrls#getDefaultOsmApiUrl}
    69      * or references the domain "dev.openstreetmap.org", otherwise they may be <code>null</code>.
     58     * <p>
     59     * Note that this may make network requests for RFC 8414 compliant endpoints.
    7060     *
    7161     * @param apiUrl The API URL for which the OAuth default parameters are created. If null or empty, the default OSM API url is used.
     
    8070
    8171        switch (oAuthVersion) {
    82             case OAuth10a:
    83                 return getDefaultOAuth10Parameters(apiUrl);
    8472            case OAuth20:
    8573            case OAuth21: // For now, OAuth 2.1 (draft) is just OAuth 2.0 with mandatory extensions, which we implement.
     
    9078    }
    9179
     80    private static JsonObject getRFC8414Parameters(String apiUrl) {
     81        HttpClient client = null;
     82        try {
     83            final URI apiURI = new URI(apiUrl);
     84            final URL rfc8414URL = new URI(apiURI.getScheme(), apiURI.getHost(),
     85                    "/.well-known/oauth-authorization-server", null).toURL();
     86            client = HttpClient.create(rfc8414URL);
     87            HttpClient.Response response = client.connect();
     88            if (response.getResponseCode() == 200) {
     89                try (BufferedReader reader = response.getContentReader();
     90                     JsonReader jsonReader = Json.createReader(reader)) {
     91                    JsonStructure structure = jsonReader.read();
     92                    if (structure.getValueType() == JsonValue.ValueType.OBJECT) {
     93                        return structure.asJsonObject();
     94                    }
     95                }
     96            }
     97        } catch (URISyntaxException | IOException e) {
     98            throw new JosmRuntimeException(e);
     99        } finally {
     100            if (client != null) {
     101                client.disconnect();
     102            }
     103        }
     104        return Json.createObjectBuilder().build();
     105    }
     106
    92107    /**
    93108     * Get the default OAuth 2.0 parameters
     
    98113        final String clientId;
    99114        final String clientSecret;
    100         final String redirectUri;
     115        final String redirectUri = "http://127.0.0.1:8111/oauth_authorization";
    101116        final String baseUrl;
    102         if (apiUrl != null && !Config.getUrls().getDefaultOsmApiUrl().equals(apiUrl) && !"http://invalid".equals(apiUrl)) {
    103             clientId = "";
    104             clientSecret = "";
    105             baseUrl = apiUrl;
    106             HttpClient client = null;
    107             redirectUri = "";
    108             // Check if the server is RFC 8414 compliant
    109             try {
    110                 client = HttpClient.create(new URL(apiUrl + (apiUrl.endsWith("/") ? "" : "/") + ".well-known/oauth-authorization-server"));
    111                 HttpClient.Response response = client.connect();
    112                 if (response.getResponseCode() == 200) {
    113                     try (BufferedReader reader = response.getContentReader();
    114                          JsonReader jsonReader = Json.createReader(reader)) {
    115                         JsonStructure structure = jsonReader.read();
    116                         if (structure.getValueType() == JsonValue.ValueType.OBJECT) {
    117                             return parseAuthorizationServerMetadataResponse(clientId, clientSecret, apiUrl,
    118                                     redirectUri, structure.asJsonObject());
    119                         }
    120                     }
    121                 }
    122             } catch (IOException | OAuthException e) {
     117        apiUrl = apiUrl == null ? OsmApi.getOsmApi().getServerUrl() : apiUrl;
     118        switch (apiUrl) {
     119            case OSM_API_DEV:
     120            case OSM_API_MASTER:
     121                // This clientId/clientSecret are provided by taylor.smock. Feel free to change if needed, but
     122                // do let one of the maintainers with server access know so that they can update the test OAuth
     123                // token.
     124                clientId = "-QZt6n1btDfqrfJNGUIMZjzcyqTgIV6sy79_W4kmQLM";
     125                // Keep secret for dev apis, just in case we want to test something that needs it.
     126                clientSecret = "SWnmRD4AdLO-2-ttHE5TR3eLF2McNf7dh0_Z2WNzJdI";
     127                break;
     128            case OSM_API_DEFAULT:
     129                clientId = "edPII614Lm0_0zEpc_QzEltA9BUll93-Y-ugRQUoHMI";
     130                // We don't actually use the client secret in our authorization flow.
     131                clientSecret = null;
     132                break;
     133            case "https://www.openhistoricalmap.org/api":
     134                // clientId provided by 1ec5 (Minh Nguyễn)
     135                clientId = "Hl5yIhFS-Egj6aY7A35ouLOuZl0EHjj8JJQQ46IO96E";
     136                clientSecret = null;
     137                break;
     138            default:
     139                clientId = "";
     140                clientSecret = null;
     141        }
     142        baseUrl = apiUrl;
     143        // Check if the server is RFC 8414 compliant
     144        try {
     145            synchronized (RFC8414_RESPONSES) {
     146                final JsonObject data;
     147                if (NetworkManager.isOffline(apiUrl)) {
     148                    data = null;
     149                } else {
     150                    data = RFC8414_RESPONSES.computeIfAbsent(apiUrl, OAuthParameters::getRFC8414Parameters);
     151                }
     152                if (data == null || data.isEmpty()) {
     153                    RFC8414_RESPONSES.remove(apiUrl);
     154                } else {
     155                    return parseAuthorizationServerMetadataResponse(clientId, clientSecret, apiUrl,
     156                            redirectUri, data);
     157                }
     158            }
     159        } catch (JosmRuntimeException e) {
     160            if (e.getCause() instanceof URISyntaxException || e.getCause() instanceof IOException) {
    123161                Logging.trace(e);
    124             } finally {
    125                 if (client != null) client.disconnect();
    126             }
    127         } else {
    128             clientId = "edPII614Lm0_0zEpc_QzEltA9BUll93-Y-ugRQUoHMI";
    129             // We don't actually use the client secret in our authorization flow.
    130             clientSecret = null;
    131             baseUrl = "https://www.openstreetmap.org/oauth2";
    132             redirectUri = "http://127.0.0.1:8111/oauth_authorization";
    133             apiUrl = OsmApi.getOsmApi().getBaseUrl();
    134         }
     162            } else {
     163                throw e;
     164            }
     165        } catch (OAuthException e) {
     166            Logging.trace(e);
     167        }
     168        // Fall back to guessing the parameters.
    135169        return new OAuth20Parameters(clientId, clientSecret, baseUrl, apiUrl, redirectUri);
    136170    }
     
    155189
    156190    /**
    157      * Get the default OAuth 1.0a parameters
    158      * @param apiUrl The api url
    159      * @return The default parameters
    160      */
    161     private static OAuthParameters getDefaultOAuth10Parameters(String apiUrl) {
    162         final String consumerKey;
    163         final String consumerSecret;
    164         final String serverUrl;
    165 
    166         if (apiUrl != null && !Config.getUrls().getDefaultOsmApiUrl().equals(apiUrl)) {
    167             consumerKey = ""; // a custom consumer key is required
    168             consumerSecret = ""; // a custom consumer secret is requireds
    169             serverUrl = apiUrl.replaceAll("/api$", "");
    170         } else {
    171             consumerKey = DEFAULT_JOSM_CONSUMER_KEY;
    172             consumerSecret = DEFAULT_JOSM_CONSUMER_SECRET;
    173             serverUrl = Config.getUrls().getOSMWebsite();
    174         }
    175 
    176         return new OAuthParameters(
    177                 consumerKey,
    178                 consumerSecret,
    179                 serverUrl + "/oauth/request_token",
    180                 serverUrl + "/oauth/access_token",
    181                 serverUrl + "/oauth/authorize",
    182                 serverUrl + "/login",
    183                 serverUrl + "/logout");
    184     }
    185 
    186     /**
    187      * Replies a set of parameters as defined in the preferences.
    188      *
    189      * @param apiUrl the API URL. Must not be null.
    190      * @return the parameters
    191      */
    192     public static OAuthParameters createFromApiUrl(String apiUrl) {
    193         return (OAuthParameters) createFromApiUrl(apiUrl, OAuthVersion.OAuth10a);
    194     }
    195 
    196     /**
    197191     * Replies a set of parameters as defined in the preferences.
    198192     *
     
    205199        IOAuthParameters parameters = createDefault(apiUrl, oAuthVersion);
    206200        switch (oAuthVersion) {
    207             case OAuth10a:
    208                 OAuthParameters oauth10aParameters = (OAuthParameters) parameters;
    209                 return new OAuthParameters(
    210                     Config.getPref().get("oauth.settings.consumer-key", oauth10aParameters.getConsumerKey()),
    211                     Config.getPref().get("oauth.settings.consumer-secret", oauth10aParameters.getConsumerSecret()),
    212                     Config.getPref().get("oauth.settings.request-token-url", oauth10aParameters.getRequestTokenUrl()),
    213                     Config.getPref().get("oauth.settings.access-token-url", oauth10aParameters.getAccessTokenUrl()),
    214                     Config.getPref().get("oauth.settings.authorise-url", oauth10aParameters.getAuthoriseUrl()),
    215                     Config.getPref().get("oauth.settings.osm-login-url", oauth10aParameters.getOsmLoginUrl()),
    216                     Config.getPref().get("oauth.settings.osm-logout-url", oauth10aParameters.getOsmLogoutUrl()));
    217201            case OAuth20:
    218202            case OAuth21: // Right now, OAuth 2.1 will work with our OAuth 2.0 implementation
     
    229213        }
    230214    }
    231 
    232     /**
    233      * Remembers the current values in the preferences.
    234      */
    235     @Override
    236     public void rememberPreferences() {
    237         Config.getPref().put("oauth.settings.consumer-key", getConsumerKey());
    238         Config.getPref().put("oauth.settings.consumer-secret", getConsumerSecret());
    239         Config.getPref().put("oauth.settings.request-token-url", getRequestTokenUrl());
    240         Config.getPref().put("oauth.settings.access-token-url", getAccessTokenUrl());
    241         Config.getPref().put("oauth.settings.authorise-url", getAuthoriseUrl());
    242         Config.getPref().put("oauth.settings.osm-login-url", getOsmLoginUrl());
    243         Config.getPref().put("oauth.settings.osm-logout-url", getOsmLogoutUrl());
    244     }
    245 
    246     private final String consumerKey;
    247     private final String consumerSecret;
    248     private final String requestTokenUrl;
    249     private final String accessTokenUrl;
    250     private final String authoriseUrl;
    251     private final String osmLoginUrl;
    252     private final String osmLogoutUrl;
    253 
    254     /**
    255      * Constructs a new {@code OAuthParameters}.
    256      * @param consumerKey consumer key
    257      * @param consumerSecret consumer secret
    258      * @param requestTokenUrl request token URL
    259      * @param accessTokenUrl access token URL
    260      * @param authoriseUrl authorise URL
    261      * @param osmLoginUrl the OSM login URL (for automatic mode)
    262      * @param osmLogoutUrl the OSM logout URL (for automatic mode)
    263      * @see #createDefault
    264      * @see #createFromApiUrl
    265      * @since 9220
    266      */
    267     public OAuthParameters(String consumerKey, String consumerSecret,
    268                            String requestTokenUrl, String accessTokenUrl, String authoriseUrl, String osmLoginUrl, String osmLogoutUrl) {
    269         this.consumerKey = consumerKey;
    270         this.consumerSecret = consumerSecret;
    271         this.requestTokenUrl = requestTokenUrl;
    272         this.accessTokenUrl = accessTokenUrl;
    273         this.authoriseUrl = authoriseUrl;
    274         this.osmLoginUrl = osmLoginUrl;
    275         this.osmLogoutUrl = osmLogoutUrl;
    276     }
    277 
    278     /**
    279      * Creates a clone of the parameters in <code>other</code>.
    280      *
    281      * @param other the other parameters. Must not be null.
    282      * @throws IllegalArgumentException if other is null
    283      */
    284     public OAuthParameters(OAuthParameters other) {
    285         CheckParameterUtil.ensureParameterNotNull(other, "other");
    286         this.consumerKey = other.consumerKey;
    287         this.consumerSecret = other.consumerSecret;
    288         this.accessTokenUrl = other.accessTokenUrl;
    289         this.requestTokenUrl = other.requestTokenUrl;
    290         this.authoriseUrl = other.authoriseUrl;
    291         this.osmLoginUrl = other.osmLoginUrl;
    292         this.osmLogoutUrl = other.osmLogoutUrl;
    293     }
    294 
    295     /**
    296      * Gets the consumer key.
    297      * @return The consumer key
    298      */
    299     public String getConsumerKey() {
    300         return consumerKey;
    301     }
    302 
    303     /**
    304      * Gets the consumer secret.
    305      * @return The consumer secret
    306      */
    307     public String getConsumerSecret() {
    308         return consumerSecret;
    309     }
    310 
    311     /**
    312      * Gets the request token URL.
    313      * @return The request token URL
    314      */
    315     public String getRequestTokenUrl() {
    316         return requestTokenUrl;
    317     }
    318 
    319     /**
    320      * Gets the access token URL.
    321      * @return The access token URL
    322      */
    323     @Override
    324     public String getAccessTokenUrl() {
    325         return accessTokenUrl;
    326     }
    327 
    328     @Override
    329     public String getAuthorizationUrl() {
    330         return this.authoriseUrl;
    331     }
    332 
    333     @Override
    334     public OAuthVersion getOAuthVersion() {
    335         return OAuthVersion.OAuth10a;
    336     }
    337 
    338     @Override
    339     public String getClientId() {
    340         return this.consumerKey;
    341     }
    342 
    343     @Override
    344     public String getClientSecret() {
    345         return this.consumerSecret;
    346     }
    347 
    348     /**
    349      * Gets the authorise URL.
    350      * @return The authorise URL
    351      */
    352     public String getAuthoriseUrl() {
    353         return this.getAuthorizationUrl();
    354     }
    355 
    356     /**
    357      * Gets the URL used to login users on the website (for automatic mode).
    358      * @return The URL used to login users
    359      */
    360     public String getOsmLoginUrl() {
    361         return osmLoginUrl;
    362     }
    363 
    364     /**
    365      * Gets the URL used to logout users on the website (for automatic mode).
    366      * @return The URL used to logout users
    367      */
    368     public String getOsmLogoutUrl() {
    369         return osmLogoutUrl;
    370     }
    371 
    372     /**
    373      * Builds an {@link OAuthConsumer} based on these parameters.
    374      *
    375      * @return the consumer
    376      */
    377     public OAuthConsumer buildConsumer() {
    378         return new SignpostAdapters.OAuthConsumer(consumerKey, consumerSecret);
    379     }
    380 
    381     /**
    382      * Builds an {@link OAuthProvider} based on these parameters and a OAuth consumer <code>consumer</code>.
    383      *
    384      * @param consumer the consumer. Must not be null.
    385      * @return the provider
    386      * @throws IllegalArgumentException if consumer is null
    387      */
    388     public OAuthProvider buildProvider(OAuthConsumer consumer) {
    389         CheckParameterUtil.ensureParameterNotNull(consumer, "consumer");
    390         return new SignpostAdapters.OAuthProvider(
    391                 requestTokenUrl,
    392                 accessTokenUrl,
    393                 authoriseUrl
    394         );
    395     }
    396 
    397     @Override
    398     public boolean equals(Object o) {
    399         if (this == o) return true;
    400         if (o == null || getClass() != o.getClass()) return false;
    401         OAuthParameters that = (OAuthParameters) o;
    402         return Objects.equals(consumerKey, that.consumerKey) &&
    403                 Objects.equals(consumerSecret, that.consumerSecret) &&
    404                 Objects.equals(requestTokenUrl, that.requestTokenUrl) &&
    405                 Objects.equals(accessTokenUrl, that.accessTokenUrl) &&
    406                 Objects.equals(authoriseUrl, that.authoriseUrl) &&
    407                 Objects.equals(osmLoginUrl, that.osmLoginUrl) &&
    408                 Objects.equals(osmLogoutUrl, that.osmLogoutUrl);
    409     }
    410 
    411     @Override
    412     public int hashCode() {
    413         return Objects.hash(consumerKey, consumerSecret, requestTokenUrl, accessTokenUrl, authoriseUrl, osmLoginUrl, osmLogoutUrl);
    414     }
    415215}
  • trunk/src/org/openstreetmap/josm/data/oauth/OAuthVersion.java

    r18650 r18991  
    88 */
    99public enum OAuthVersion {
    10     /** <a href="https://oauth.net/core/1.0a/">OAuth 1.0a</a> */
     10    /**
     11     * <a href="https://oauth.net/core/1.0a/">OAuth 1.0a</a>
     12     * @deprecated The OSM API server has deprecated and will remove OAuth 1.0a support in June 2024.
     13     */
     14    @Deprecated
    1115    OAuth10a,
    1216    /** <a href="https://datatracker.ietf.org/doc/html/rfc6749">OAuth 2.0</a> */
  • trunk/src/org/openstreetmap/josm/gui/oauth/AbstractAuthorizationUI.java

    r18650 r18991  
    55
    66import org.openstreetmap.josm.data.oauth.IOAuthParameters;
     7import org.openstreetmap.josm.data.oauth.IOAuthToken;
    78import org.openstreetmap.josm.data.oauth.OAuthParameters;
    8 import org.openstreetmap.josm.data.oauth.OAuthToken;
    99import org.openstreetmap.josm.data.oauth.OAuthVersion;
    1010import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
     
    2323
    2424    private String apiUrl;
    25     private final AdvancedOAuthPropertiesPanel pnlAdvancedProperties = new AdvancedOAuthPropertiesPanel(OAuthVersion.OAuth10a);
    26     private transient OAuthToken accessToken;
    27 
    28     /**
    29      * Constructs a new {@code AbstractAuthorizationUI} without API URL.
    30      * @since 10189
    31      */
    32     protected AbstractAuthorizationUI() {
    33     }
     25    private final AdvancedOAuthPropertiesPanel pnlAdvancedProperties;
     26    private transient IOAuthToken accessToken;
    3427
    3528    /**
    3629     * Constructs a new {@code AbstractAuthorizationUI} for the given API URL.
    37      * @param apiUrl The OSM API URL
    38      * @since 5422
     30     * @param apiUrl The OSM API URL (may be null)
     31     * @param oAuthVersion The oauth version to use
     32     * @since 18991
    3933     */
    40     protected AbstractAuthorizationUI(String apiUrl) {
    41         setApiUrl(apiUrl);
     34    protected AbstractAuthorizationUI(String apiUrl, OAuthVersion oAuthVersion) {
     35        this.pnlAdvancedProperties = new AdvancedOAuthPropertiesPanel(oAuthVersion);
     36        if (apiUrl != null) {
     37            setApiUrl(apiUrl);
     38        }
    4239    }
    4340
    44     protected void fireAccessTokenChanged(OAuthToken oldValue, OAuthToken newValue) {
     41    protected void fireAccessTokenChanged(IOAuthToken oldValue, IOAuthToken newValue) {
    4542        firePropertyChange(ACCESS_TOKEN_PROP, oldValue, newValue);
    4643    }
     
    9188     * @return the retrieved Access Token
    9289     */
    93     public OAuthToken getAccessToken() {
     90    public IOAuthToken getAccessToken() {
    9491        return accessToken;
    9592    }
     
    10198     * @param accessToken the new access token. null, to clear the current access token
    10299     */
    103     protected void setAccessToken(OAuthToken accessToken) {
    104         OAuthToken oldValue = this.accessToken;
     100    protected void setAccessToken(IOAuthToken accessToken) {
     101        IOAuthToken oldValue = this.accessToken;
    105102        this.accessToken = accessToken;
    106103        if (oldValue == null ^ this.accessToken == null) {
     
    111108            fireAccessTokenChanged(oldValue, this.accessToken);
    112109        }
     110    }
     111
     112    /**
     113     * Get the OAuth version for this AuthorizationUI
     114     * @return The OAuth version
     115     * @since 18991
     116     */
     117    public OAuthVersion getOAuthVersion() {
     118        return this.pnlAdvancedProperties.getAdvancedParameters().getOAuthVersion();
    113119    }
    114120
  • trunk/src/org/openstreetmap/josm/gui/oauth/AccessTokenInfoPanel.java

    r14977 r18991  
    1212import javax.swing.JPanel;
    1313
     14import org.openstreetmap.josm.data.oauth.IOAuthToken;
     15import org.openstreetmap.josm.data.oauth.OAuth20Token;
    1416import org.openstreetmap.josm.data.oauth.OAuthAccessTokenHolder;
    15 import org.openstreetmap.josm.data.oauth.OAuthToken;
    1617import org.openstreetmap.josm.gui.widgets.JosmTextField;
     18import org.openstreetmap.josm.tools.JosmRuntimeException;
    1719
    1820/**
    19  * Displays the key and the secret of an OAuth Access Token.
    20  * @since 2746
     21 * Displays the key of an OAuth Access Token.
     22 * @since 2746 (modified for OAuth 2 in 18991)
    2123 */
    2224public class AccessTokenInfoPanel extends JPanel {
    2325
    2426    private final JosmTextField tfAccessTokenKey = new JosmTextField(null, null, 0, false);
    25     private final JosmTextField tfAccessTokenSecret = new JosmTextField(null, null, 0, false);
    2627    private final JCheckBox cbSaveAccessTokenInPreferences = new JCheckBox(tr("Save Access Token in preferences"));
    2728
     
    5657        add(new JLabel(tr("Access Token Secret:")), gc);
    5758
    58         gc.gridx = 1;
    5959        gc.weightx = 1.0;
    60         add(tfAccessTokenSecret, gc);
    61         tfAccessTokenSecret.setEditable(false);
    62 
    6360        // the checkbox
    6461        gc.gridx = 0;
     
    8784     * @param token the access  token. If null, the content in the info panel is cleared
    8885     */
    89     public void setAccessToken(OAuthToken token) {
     86    public void setAccessToken(IOAuthToken token) {
    9087        if (token == null) {
    9188            tfAccessTokenKey.setText("");
    92             tfAccessTokenSecret.setText("");
    9389            return;
    9490        }
    95         tfAccessTokenKey.setText(token.getKey());
    96         tfAccessTokenSecret.setText(token.getSecret());
     91        if (token instanceof OAuth20Token) {
     92            tfAccessTokenKey.setText(((OAuth20Token) token).getBearerToken());
     93        } else {
     94            throw new JosmRuntimeException("Unknown token type: " + token.getClass());
     95        }
    9796    }
    9897
  • trunk/src/org/openstreetmap/josm/gui/oauth/AdvancedOAuthPropertiesPanel.java

    r18650 r18991  
    2222import org.openstreetmap.josm.gui.HelpAwareOptionPane;
    2323import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
     24import org.openstreetmap.josm.gui.MainApplication;
    2425import org.openstreetmap.josm.gui.help.HelpUtil;
     26import org.openstreetmap.josm.gui.util.GuiHelper;
    2527import org.openstreetmap.josm.gui.widgets.JosmTextField;
    2628import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
     
    5355    private final JosmTextField tfAccessTokenURL = new JosmTextField();
    5456    private final JosmTextField tfAuthoriseURL = new JosmTextField();
    55     private final JosmTextField tfOsmLoginURL = new JosmTextField();
    56     private final JosmTextField tfOsmLogoutURL = new JosmTextField();
    5757    private final OAuthVersion oauthVersion;
    5858    private transient UseDefaultItemListener ilUseDefault;
     
    8484        gc.weightx = 0.0;
    8585        gc.gridwidth = 1;
    86         if (this.oauthVersion == OAuthVersion.OAuth10a) {
    87             add(new JLabel(tr("Consumer Key:")), gc);
    88         } else {
    89             add(new JLabel(tr("Client ID:")), gc);
    90         }
     86        add(new JLabel(tr("Client ID:")), gc);
    9187
    9288        gc.gridx = 1;
     
    9995        gc.gridx = 0;
    10096        gc.weightx = 0.0;
    101         if (this.oauthVersion == OAuthVersion.OAuth10a) {
    102             add(new JLabel(tr("Consumer Secret:")), gc);
    103         } else {
    104             add(new JLabel(tr("Client Secret:")), gc);
    105         }
     97        add(new JLabel(tr("Client Secret:")), gc);
    10698
    10799        gc.gridx = 1;
     
    114106        gc.gridx = 0;
    115107        gc.weightx = 0.0;
    116         if (this.oauthVersion == OAuthVersion.OAuth10a) {
    117             add(new JLabel(tr("Request Token URL:")), gc);
    118         } else {
    119             add(new JLabel(tr("Redirect URL:")), gc);
    120         }
     108        add(new JLabel(tr("Redirect URL:")), gc);
    121109
    122110        gc.gridx = 1;
     
    147135        SelectAllOnFocusGainedDecorator.decorate(tfAuthoriseURL);
    148136
    149         if (this.oauthVersion == OAuthVersion.OAuth10a) {
    150             // -- OSM login URL
    151             gc.gridy++;
    152             gc.gridx = 0;
    153             gc.weightx = 0.0;
    154             add(new JLabel(tr("OSM login URL:")), gc);
    155 
    156             gc.gridx = 1;
    157             gc.weightx = 1.0;
    158             add(tfOsmLoginURL, gc);
    159             SelectAllOnFocusGainedDecorator.decorate(tfOsmLoginURL);
    160 
    161             // -- OSM logout URL
    162             gc.gridy++;
    163             gc.gridx = 0;
    164             gc.weightx = 0.0;
    165             add(new JLabel(tr("OSM logout URL:")), gc);
    166 
    167             gc.gridx = 1;
    168             gc.weightx = 1.0;
    169             add(tfOsmLogoutURL, gc);
    170             SelectAllOnFocusGainedDecorator.decorate(tfOsmLogoutURL);
    171         }
    172 
    173137        ilUseDefault = new UseDefaultItemListener();
    174138        cbUseDefaults.addItemListener(ilUseDefault);
     139        cbUseDefaults.setSelected(Config.getPref().getBoolean("oauth.settings.use-default", true));
    175140    }
    176141
    177142    protected boolean hasCustomSettings() {
    178         OAuthParameters params = OAuthParameters.createDefault(apiUrl);
     143        IOAuthParameters params = OAuthParameters.createDefault(apiUrl, OAuthVersion.OAuth20);
    179144        return !params.equals(getAdvancedParameters());
    180145    }
     
    211176
    212177    protected void resetToDefaultSettings() {
    213         cbUseDefaults.setSelected(true);
    214178        IOAuthParameters iParams = OAuthParameters.createDefault(apiUrl, this.oauthVersion);
    215         switch (this.oauthVersion) {
    216             case OAuth10a:
    217                 OAuthParameters params = (OAuthParameters) iParams;
    218                 tfConsumerKey.setText(params.getConsumerKey());
    219                 tfConsumerSecret.setText(params.getConsumerSecret());
    220                 tfRequestTokenURL.setText(params.getRequestTokenUrl());
    221                 tfAccessTokenURL.setText(params.getAccessTokenUrl());
    222                 tfAuthoriseURL.setText(params.getAuthoriseUrl());
    223                 tfOsmLoginURL.setText(params.getOsmLoginUrl());
    224                 tfOsmLogoutURL.setText(params.getOsmLogoutUrl());
    225                 break;
    226             case OAuth20:
    227             case OAuth21:
    228                 OAuth20Parameters params20 = (OAuth20Parameters) iParams;
    229                 tfConsumerKey.setText(params20.getClientId());
    230                 tfConsumerSecret.setText(params20.getClientSecret());
    231                 tfAccessTokenURL.setText(params20.getAccessTokenUrl());
    232                 tfAuthoriseURL.setText(params20.getAuthorizationUrl());
    233                 tfRequestTokenURL.setText(params20.getRedirectUri());
    234         }
    235 
    236         setChildComponentsEnabled(false);
     179        GuiHelper.runInEDTAndWaitWithException(() -> {
     180                    cbUseDefaults.setSelected(true);
     181                    switch (this.oauthVersion) {
     182                        case OAuth20:
     183                        case OAuth21:
     184                            OAuth20Parameters params20 = (OAuth20Parameters) iParams;
     185                            tfConsumerKey.setText(params20.getClientId());
     186                            tfConsumerSecret.setText(params20.getClientSecret());
     187                            tfAccessTokenURL.setText(params20.getAccessTokenUrl());
     188                            tfAuthoriseURL.setText(params20.getAuthorizationUrl());
     189                            tfRequestTokenURL.setText(params20.getRedirectUri());
     190                            break;
     191                        default:
     192                            throw new UnsupportedOperationException("Unsupported OAuth version: " + this.oauthVersion);
     193                    }
     194                    setChildComponentsEnabled(false);
     195                });
    237196    }
    238197
     
    253212        if (cbUseDefaults.isSelected())
    254213            return OAuthParameters.createDefault(apiUrl, this.oauthVersion);
    255         if (this.oauthVersion == OAuthVersion.OAuth10a) {
    256             return new OAuthParameters(
    257                     tfConsumerKey.getText(),
    258                     tfConsumerSecret.getText(),
    259                     tfRequestTokenURL.getText(),
    260                     tfAccessTokenURL.getText(),
    261                     tfAuthoriseURL.getText(),
    262                     tfOsmLoginURL.getText(),
    263                     tfOsmLogoutURL.getText());
    264         }
    265214        return new OAuth20Parameters(
    266215                tfConsumerKey.getText(),
     
    286235            cbUseDefaults.setSelected(false);
    287236            setChildComponentsEnabled(true);
    288             if (parameters instanceof OAuthParameters) {
    289                 OAuthParameters parameters10 = (OAuthParameters) parameters;
    290                 tfConsumerKey.setText(parameters10.getConsumerKey() == null ? "" : parameters10.getConsumerKey());
    291                 tfConsumerSecret.setText(parameters10.getConsumerSecret() == null ? "" : parameters10.getConsumerSecret());
    292                 tfRequestTokenURL.setText(parameters10.getRequestTokenUrl() == null ? "" : parameters10.getRequestTokenUrl());
    293                 tfAccessTokenURL.setText(parameters10.getAccessTokenUrl() == null ? "" : parameters10.getAccessTokenUrl());
    294                 tfAuthoriseURL.setText(parameters10.getAuthoriseUrl() == null ? "" : parameters10.getAuthoriseUrl());
    295                 tfOsmLoginURL.setText(parameters10.getOsmLoginUrl() == null ? "" : parameters10.getOsmLoginUrl());
    296                 tfOsmLogoutURL.setText(parameters10.getOsmLogoutUrl() == null ? "" : parameters10.getOsmLogoutUrl());
    297             } else if (parameters instanceof OAuth20Parameters) {
     237            if (parameters instanceof OAuth20Parameters) {
    298238                OAuth20Parameters parameters20 = (OAuth20Parameters) parameters;
    299239                tfConsumerKey.setText(parameters20.getClientId());
     
    317257        boolean useDefault = Config.getPref().getBoolean("oauth.settings.use-default", true);
    318258        ilUseDefault.setEnabled(false);
    319         if (useDefault) {
    320             resetToDefaultSettings();
    321         } else {
    322             setAdvancedParameters(OAuthParameters.createFromApiUrl(paramApiUrl));
    323         }
    324         ilUseDefault.setEnabled(true);
     259        MainApplication.worker.execute(() -> {
     260            if (useDefault) {
     261                this.resetToDefaultSettings();
     262            } else {
     263                setAdvancedParameters(OAuthParameters.createFromApiUrl(paramApiUrl, OAuthVersion.OAuth20));
     264            }
     265            GuiHelper.runInEDT(() -> ilUseDefault.setEnabled(true));
     266        });
    325267    }
    326268
     
    331273        Config.getPref().putBoolean("oauth.settings.use-default", cbUseDefaults.isSelected());
    332274        if (cbUseDefaults.isSelected()) {
    333             new OAuthParameters(null, null, null, null, null, null, null).rememberPreferences();
     275            MainApplication.worker.execute(() -> OAuthParameters.createDefault().rememberPreferences());
    334276        } else {
    335277            getAdvancedParameters().rememberPreferences();
     
    349291                    return;
    350292                }
    351                 resetToDefaultSettings();
     293                MainApplication.worker.execute(AdvancedOAuthPropertiesPanel.this::resetToDefaultSettings);
    352294                break;
    353295            case ItemEvent.DESELECTED:
     
    372314        this.apiUrl = apiUrl;
    373315        if (cbUseDefaults.isSelected()) {
    374             resetToDefaultSettings();
     316            MainApplication.worker.execute(this::resetToDefaultSettings);
    375317        }
    376318    }
  • trunk/src/org/openstreetmap/josm/gui/oauth/FullyAutomaticAuthorizationUI.java

    r18650 r18991  
    1313import java.awt.event.ActionEvent;
    1414import java.io.IOException;
    15 import java.net.Authenticator.RequestorType;
    16 import java.net.PasswordAuthentication;
    1715import java.util.concurrent.Executor;
    1816
     
    2422import javax.swing.JPanel;
    2523import javax.swing.JTabbedPane;
    26 import javax.swing.event.DocumentEvent;
    27 import javax.swing.event.DocumentListener;
    28 import javax.swing.text.JTextComponent;
    2924import javax.swing.text.html.HTMLEditorKit;
    3025
    31 import org.openstreetmap.josm.data.oauth.OAuthParameters;
    32 import org.openstreetmap.josm.data.oauth.OAuthToken;
     26import org.openstreetmap.josm.data.oauth.IOAuthToken;
     27import org.openstreetmap.josm.data.oauth.OAuthVersion;
    3328import org.openstreetmap.josm.gui.HelpAwareOptionPane;
    3429import org.openstreetmap.josm.gui.PleaseWaitRunnable;
    3530import org.openstreetmap.josm.gui.help.HelpUtil;
    36 import org.openstreetmap.josm.gui.preferences.server.UserNameValidator;
    3731import org.openstreetmap.josm.gui.util.GuiHelper;
    38 import org.openstreetmap.josm.gui.widgets.DefaultTextComponentValidator;
    3932import org.openstreetmap.josm.gui.widgets.HtmlPanel;
    4033import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
    41 import org.openstreetmap.josm.gui.widgets.JosmPasswordField;
    42 import org.openstreetmap.josm.gui.widgets.JosmTextField;
    43 import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
    4434import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel;
    45 import org.openstreetmap.josm.io.OsmApi;
    4635import org.openstreetmap.josm.io.OsmTransferException;
    47 import org.openstreetmap.josm.io.auth.CredentialsAgent;
    48 import org.openstreetmap.josm.io.auth.CredentialsAgentException;
    49 import org.openstreetmap.josm.io.auth.CredentialsManager;
    5036import org.openstreetmap.josm.tools.ImageProvider;
    5137import org.openstreetmap.josm.tools.Logging;
    52 import org.openstreetmap.josm.tools.Utils;
    5338import org.xml.sax.SAXException;
    5439
    5540/**
    56  * This is an UI which supports a JOSM user to get an OAuth Access Token in a fully
     41 * This is a UI which supports a JOSM user to get an OAuth Access Token in a fully
    5742 * automatic process.
    5843 *
     
    6045 */
    6146public class FullyAutomaticAuthorizationUI extends AbstractAuthorizationUI {
    62 
    63     private final JosmTextField tfUserName = new JosmTextField();
    64     private final JosmPasswordField tfPassword = new JosmPasswordField();
    65     private transient UserNameValidator valUserName;
    66     private transient PasswordValidator valPassword;
    6747    private final AccessTokenInfoPanel pnlAccessTokenInfo = new AccessTokenInfoPanel();
    6848    private OsmPrivilegesPanel pnlOsmPrivileges;
     
    10585                + tr("Please enter your OSM user name and password. The password will <strong>not</strong> be saved "
    10686                        + "in clear text in the JOSM preferences and it will be submitted to the OSM server <strong>only once</strong>. "
    107                         + "Subsequent data upload requests don''t use your password any more.").replaceAll("\\. ", ".<br>")
     87                        + "Subsequent data upload requests don''t use your password any more.").replace(". ", ".<br>")
    10888                        + "</p>"
    10989                        + "</body></html>");
     
    11999        pnl.add(new JLabel(tr("Username: ")), gc);
    120100
    121         gc.gridx = 1;
    122         gc.weightx = 1.0;
    123         pnl.add(tfUserName, gc);
    124         SelectAllOnFocusGainedDecorator.decorate(tfUserName);
    125         valUserName = new UserNameValidator(tfUserName);
    126         valUserName.validate();
    127 
    128101        // the password input field
    129102        gc.anchor = GridBagConstraints.NORTHWEST;
     
    134107        pnl.add(new JLabel(tr("Password:")), gc);
    135108
     109        // filler - grab remaining space
    136110        gc.gridx = 1;
    137         gc.weightx = 1.0;
    138         pnl.add(tfPassword, gc);
    139         SelectAllOnFocusGainedDecorator.decorate(tfPassword);
    140         valPassword = new PasswordValidator(tfPassword);
    141         valPassword.validate();
    142 
    143         // filler - grab remaining space
    144111        gc.gridy = 4;
    145112        gc.gridwidth = 2;
     
    168135
    169136    /**
    170      * Initializes the panel with values from the preferences
    171      * @param paramApiUrl the API URL
    172      */
    173     @Override
    174     public void initialize(String paramApiUrl) {
    175         super.initialize(paramApiUrl);
    176         CredentialsAgent cm = CredentialsManager.getInstance();
    177         try {
    178             PasswordAuthentication pa = cm.lookup(RequestorType.SERVER, OsmApi.getOsmApi().getHost());
    179             if (pa == null) {
    180                 tfUserName.setText("");
    181                 tfPassword.setText("");
    182             } else {
    183                 tfUserName.setText(pa.getUserName() == null ? "" : pa.getUserName());
    184                 tfPassword.setText(pa.getPassword() == null ? "" : String.valueOf(pa.getPassword()));
    185             }
    186         } catch (CredentialsAgentException e) {
    187             Logging.error(e);
    188             tfUserName.setText("");
    189             tfPassword.setText("");
    190         }
    191     }
    192 
    193     /**
    194137     * Builds the panel with the action button  for starting the authorisation
    195138     *
     
    200143
    201144        RunAuthorisationAction runAuthorisationAction = new RunAuthorisationAction();
    202         tfPassword.getDocument().addDocumentListener(runAuthorisationAction);
    203         tfUserName.getDocument().addDocumentListener(runAuthorisationAction);
    204145        pnl.add(new JButton(runAuthorisationAction));
    205146        return pnl;
     
    289230    }
    290231
    291     protected String getOsmUserName() {
    292         return tfUserName.getText();
    293     }
    294 
    295     protected String getOsmPassword() {
    296         return String.valueOf(tfPassword.getPassword());
    297     }
    298 
    299232    /**
    300233     * Constructs a new {@code FullyAutomaticAuthorizationUI} for the given API URL.
     
    302235     * @param executor the executor used for running the HTTP requests for the authorization
    303236     * @since 5422
    304      */
     237     * @deprecated since 18991
     238     */
     239    @Deprecated
    305240    public FullyAutomaticAuthorizationUI(String apiUrl, Executor executor) {
    306         super(apiUrl);
     241        this(apiUrl, executor, OAuthVersion.OAuth10a);
     242    }
     243
     244    /**
     245     * Constructs a new {@code FullyAutomaticAuthorizationUI} for the given API URL.
     246     * @param apiUrl The OSM API URL
     247     * @param executor the executor used for running the HTTP requests for the authorization
     248     * @param oAuthVersion The OAuth version to use for this UI
     249     * @since 18991
     250     */
     251    public FullyAutomaticAuthorizationUI(String apiUrl, Executor executor, OAuthVersion oAuthVersion) {
     252        super(apiUrl, oAuthVersion);
    307253        this.executor = executor;
    308254        build();
     
    315261
    316262    @Override
    317     protected void setAccessToken(OAuthToken accessToken) {
     263    protected void setAccessToken(IOAuthToken accessToken) {
    318264        super.setAccessToken(accessToken);
    319265        pnlAccessTokenInfo.setAccessToken(accessToken);
     
    323269     * Starts the authorisation process
    324270     */
    325     class RunAuthorisationAction extends AbstractAction implements DocumentListener {
     271    class RunAuthorisationAction extends AbstractAction {
    326272        RunAuthorisationAction() {
    327273            putValue(NAME, tr("Authorize now"));
    328274            new ImageProvider("oauth", "oauth-small").getResource().attachImageIcon(this);
    329275            putValue(SHORT_DESCRIPTION, tr("Click to redirect you to the authorization form on the JOSM web site"));
    330             updateEnabledState();
    331276        }
    332277
     
    334279        public void actionPerformed(ActionEvent evt) {
    335280            executor.execute(new FullyAutomaticAuthorisationTask(FullyAutomaticAuthorizationUI.this));
    336         }
    337 
    338         protected final void updateEnabledState() {
    339             setEnabled(valPassword.isValid() && valUserName.isValid());
    340         }
    341 
    342         @Override
    343         public void changedUpdate(DocumentEvent e) {
    344             updateEnabledState();
    345         }
    346 
    347         @Override
    348         public void insertUpdate(DocumentEvent e) {
    349             updateEnabledState();
    350         }
    351 
    352         @Override
    353         public void removeUpdate(DocumentEvent e) {
    354             updateEnabledState();
    355281        }
    356282    }
     
    386312                    FullyAutomaticAuthorizationUI.this,
    387313                    getApiUrl(),
    388                     (OAuthParameters) getAdvancedPropertiesPanel().getAdvancedParameters(),
    389314                    getAccessToken()
    390315            ));
    391         }
    392     }
    393 
    394     static class PasswordValidator extends DefaultTextComponentValidator {
    395         PasswordValidator(JTextComponent tc) {
    396             super(tc, tr("Please enter your OSM password"), tr("The password cannot be empty. Please enter your OSM password"));
    397316        }
    398317    }
     
    439358                            + "Please check your advanced setting and try again."
    440359                            + "</html>",
    441                             ((OAuthParameters) getAdvancedPropertiesPanel().getAdvancedParameters()).getAuthoriseUrl()),
     360                            getAdvancedPropertiesPanel().getAdvancedParameters().getAuthorizationUrl()),
    442361                    tr("OAuth authorization failed"),
    443362                    JOptionPane.ERROR_MESSAGE,
     
    446365        }
    447366
    448         protected void alertLoginFailed() {
    449             final String loginUrl = ((OAuthParameters) getAdvancedPropertiesPanel().getAdvancedParameters()).getOsmLoginUrl();
    450             HelpAwareOptionPane.showOptionDialog(
    451                     FullyAutomaticAuthorizationUI.this,
    452                     tr("<html>"
    453                             + "The automatic process for retrieving an OAuth Access Token<br>"
    454                             + "from the OSM server failed. JOSM failed to log into {0}<br>"
    455                             + "for user {1}.<br><br>"
    456                             + "Please check username and password and try again."
    457                             +"</html>",
    458                             loginUrl,
    459                             Utils.escapeReservedCharactersHTML(getOsmUserName())),
    460                     tr("OAuth authorization failed"),
    461                     JOptionPane.ERROR_MESSAGE,
    462                     HelpUtil.ht("/Dialog/OAuthAuthorisationWizard#FullyAutomaticProcessFailed")
    463             );
    464         }
    465 
    466367        protected void handleException(final OsmOAuthAuthorizationException e) {
    467             Runnable r = () -> {
    468                 if (e instanceof OsmLoginFailedException) {
    469                     alertLoginFailed();
    470                 } else {
    471                     alertAuthorisationFailed();
     368            Logging.error(e);
     369            GuiHelper.runInEDT(this::alertAuthorisationFailed);
     370        }
     371
     372        @Override
     373        protected void realRun() throws SAXException, IOException, OsmTransferException {
     374            getProgressMonitor().setTicksCount(2);
     375            OAuthAuthorizationWizard.authorize(true, token -> {
     376                if (!canceled) {
     377                    getProgressMonitor().worked(1);
     378                    GuiHelper.runInEDT(() -> {
     379                        prepareUIForResultDisplay();
     380                        setAccessToken(token.orElse(null));
     381                    });
    472382                }
    473             };
    474             Logging.error(e);
    475             GuiHelper.runInEDT(r);
    476         }
    477 
    478         @Override
    479         protected void realRun() throws SAXException, IOException, OsmTransferException {
    480             try {
    481                 getProgressMonitor().setTicksCount(3);
    482                 OsmOAuthAuthorizationClient authClient = new OsmOAuthAuthorizationClient(
    483                         (OAuthParameters) getAdvancedPropertiesPanel().getAdvancedParameters()
    484                 );
    485                 OAuthToken requestToken = authClient.getRequestToken(
    486                         getProgressMonitor().createSubTaskMonitor(1, false)
    487                 );
    488                 getProgressMonitor().worked(1);
    489                 if (canceled) return;
    490                 authClient.authorise(
    491                         requestToken,
    492                         getOsmUserName(),
    493                         getOsmPassword(),
    494                         pnlOsmPrivileges.getPrivileges(),
    495                         getProgressMonitor().createSubTaskMonitor(1, false)
    496                 );
    497                 getProgressMonitor().worked(1);
    498                 if (canceled) return;
    499                 final OAuthToken accessToken = authClient.getAccessToken(
    500                         getProgressMonitor().createSubTaskMonitor(1, false)
    501                 );
    502                 getProgressMonitor().worked(1);
    503                 if (canceled) return;
    504                 GuiHelper.runInEDT(() -> {
    505                     prepareUIForResultDisplay();
    506                     setAccessToken(accessToken);
    507                 });
    508             } catch (final OsmOAuthAuthorizationException e) {
    509                 handleException(e);
    510             }
     383            }, getApiUrl(), getOAuthVersion());
     384            getProgressMonitor().worked(1);
    511385        }
    512386    }
  • trunk/src/org/openstreetmap/josm/gui/oauth/ManualAuthorizationUI.java

    r18650 r18991  
    2525import javax.swing.text.JTextComponent;
    2626
     27import org.openstreetmap.josm.data.oauth.OAuth20Exception;
     28import org.openstreetmap.josm.data.oauth.OAuth20Token;
    2729import org.openstreetmap.josm.data.oauth.OAuthAccessTokenHolder;
    28 import org.openstreetmap.josm.data.oauth.OAuthParameters;
    29 import org.openstreetmap.josm.data.oauth.OAuthToken;
     30import org.openstreetmap.josm.data.oauth.OAuthVersion;
    3031import org.openstreetmap.josm.gui.widgets.DefaultTextComponentValidator;
    3132import org.openstreetmap.josm.gui.widgets.HtmlPanel;
     
    3334import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
    3435import org.openstreetmap.josm.tools.ImageProvider;
     36import org.openstreetmap.josm.tools.JosmRuntimeException;
    3537
    3638/**
     
    4345    private final JosmTextField tfAccessTokenKey = new JosmTextField();
    4446    private transient AccessTokenKeyValidator valAccessTokenKey;
    45     private final JosmTextField tfAccessTokenSecret = new JosmTextField();
    46     private transient AccessTokenSecretValidator valAccessTokenSecret;
    4747    private final JCheckBox cbSaveToPreferences = new JCheckBox(tr("Save Access Token in preferences"));
    4848    private final HtmlPanel pnlMessage = new HtmlPanel();
     
    5454     * @param executor the executor used for running the HTTP requests for the authorization
    5555     * @since 5422
     56     * @deprecated since 18991, use {@link ManualAuthorizationUI#ManualAuthorizationUI(String, Executor, OAuthVersion)}
     57     * instead.
    5658     */
     59    @Deprecated
    5760    public ManualAuthorizationUI(String apiUrl, Executor executor) {
    58         super(/* dont pass apiURL because setApiUrl is overridden and references a local field */);
     61        this(apiUrl, executor, OAuthVersion.OAuth10a);
     62    }
     63
     64    /**
     65     * Constructs a new {@code ManualAuthorizationUI} for the given API URL.
     66     * @param apiUrl The OSM API URL
     67     * @param executor the executor used for running the HTTP requests for the authorization
     68     * @param oAuthVersion The OAuthVersion to use for this UI
     69     * @since 18991
     70     */
     71    public ManualAuthorizationUI(String apiUrl, Executor executor, OAuthVersion oAuthVersion) {
     72        super(null /* don't pass apiURL because setApiUrl is overridden and references a local field */,
     73                oAuthVersion);
    5974        setApiUrl(apiUrl);
    6075        this.executor = executor;
     
    95110        tfAccessTokenKey.getDocument().addDocumentListener(accessTokenBuilder);
    96111
    97         // the access token key input field
    98         gc.gridy = 2;
    99         gc.gridx = 0;
    100         gc.weightx = 0.0;
    101         pnl.add(new JLabel(tr("Access Token Secret:")), gc);
    102 
    103         gc.gridx = 1;
    104         gc.weightx = 1.0;
    105         pnl.add(tfAccessTokenSecret, gc);
    106         SelectAllOnFocusGainedDecorator.decorate(tfAccessTokenSecret);
    107         valAccessTokenSecret = new AccessTokenSecretValidator(tfAccessTokenSecret);
    108         valAccessTokenSecret.validate();
    109         tfAccessTokenSecret.getDocument().addDocumentListener(accessTokenBuilder);
    110 
    111112        // the checkbox for saving to preferences
    112113        gc.gridy = 3;
     
    185186    }
    186187
    187     private static class AccessTokenSecretValidator extends DefaultTextComponentValidator {
    188         AccessTokenSecretValidator(JTextComponent tc) {
    189             super(tc, tr("Please enter an Access Token Secret"),
    190                       tr("The Access Token Secret must not be empty. Please enter an Access Token Secret"));
    191         }
    192     }
    193 
    194188    class AccessTokenBuilder implements DocumentListener {
    195189
    196190        public void build() {
    197             if (!valAccessTokenKey.isValid() || !valAccessTokenSecret.isValid()) {
     191            if (!valAccessTokenKey.isValid()) {
    198192                setAccessToken(null);
    199193            } else {
    200                 setAccessToken(new OAuthToken(tfAccessTokenKey.getText().trim(), tfAccessTokenSecret.getText().trim()));
     194                try {
     195                    setAccessToken(new OAuth20Token(getOAuthParameters(), "{\"token_type\":\"bearer\", \"access_token\""
     196                            + tfAccessTokenKey.getText().trim() + "\"}"));
     197                } catch (OAuth20Exception e) {
     198                    throw new JosmRuntimeException(e);
     199                }
    201200            }
    202201        }
     
    234233                    ManualAuthorizationUI.this,
    235234                    getApiUrl(),
    236                     (OAuthParameters) getAdvancedPropertiesPanel().getAdvancedParameters(),
    237235                    getAccessToken()
    238236            );
  • trunk/src/org/openstreetmap/josm/gui/oauth/OAuthAuthorizationWizard.java

    r18650 r18991  
    2020import java.net.URL;
    2121import java.util.Objects;
     22import java.util.Optional;
    2223import java.util.concurrent.Executor;
    2324import java.util.concurrent.FutureTask;
     25import java.util.function.Consumer;
    2426
    2527import javax.swing.AbstractAction;
     
    2729import javax.swing.JButton;
    2830import javax.swing.JDialog;
     31import javax.swing.JOptionPane;
    2932import javax.swing.JPanel;
    3033import javax.swing.JScrollPane;
     
    3336import javax.swing.text.html.HTMLEditorKit;
    3437
     38import org.openstreetmap.josm.data.oauth.IOAuthParameters;
     39import org.openstreetmap.josm.data.oauth.IOAuthToken;
     40import org.openstreetmap.josm.data.oauth.OAuth20Authorization;
    3541import org.openstreetmap.josm.data.oauth.OAuthAccessTokenHolder;
    3642import org.openstreetmap.josm.data.oauth.OAuthParameters;
    37 import org.openstreetmap.josm.data.oauth.OAuthToken;
     43import org.openstreetmap.josm.data.oauth.OAuthVersion;
     44import org.openstreetmap.josm.data.oauth.osm.OsmScopes;
    3845import org.openstreetmap.josm.gui.MainApplication;
    3946import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
     
    4350import org.openstreetmap.josm.gui.widgets.HtmlPanel;
    4451import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
     52import org.openstreetmap.josm.io.auth.CredentialsManager;
     53import org.openstreetmap.josm.io.remotecontrol.RemoteControl;
    4554import org.openstreetmap.josm.spi.preferences.Config;
    4655import org.openstreetmap.josm.tools.GBC;
     
    5968    private final AuthorizationProcedure procedure;
    6069    private final String apiUrl;
     70    private final OAuthVersion oAuthVersion;
    6171
    6272    private FullyAutomaticAuthorizationUI pnlFullyAutomaticAuthorisationUI;
    63     private SemiAutomaticAuthorizationUI pnlSemiAutomaticAuthorisationUI;
    6473    private ManualAuthorizationUI pnlManualAuthorisationUI;
    6574    private JScrollPane spAuthorisationProcedureUI;
     
    6776
    6877    /**
    69      * Launches the wizard, {@link OAuthAccessTokenHolder#setAccessToken(OAuthToken) sets the token}
     78     * Launches the wizard, {@link OAuthAccessTokenHolder#setAccessToken(String, IOAuthToken)} sets the token
    7079     * and {@link OAuthAccessTokenHolder#setSaveToPreferences(boolean) saves to preferences}.
     80     * @param callback Callback to run when authorization is finished
    7181     * @throws UserCancelException if user cancels the operation
    7282     */
    73     public void showDialog() throws UserCancelException {
    74         setVisible(true);
    75         if (isCanceled()) {
    76             throw new UserCancelException();
     83    public void showDialog(Consumer<Optional<IOAuthToken>> callback) throws UserCancelException {
     84        if ((this.oAuthVersion == OAuthVersion.OAuth20 || this.oAuthVersion == OAuthVersion.OAuth21)
     85        && this.procedure == AuthorizationProcedure.FULLY_AUTOMATIC) {
     86            authorize(true, callback, this.apiUrl, this.oAuthVersion);
     87        } else {
     88            setVisible(true);
     89            if (isCanceled()) {
     90                throw new UserCancelException();
     91            }
    7792        }
    7893        OAuthAccessTokenHolder holder = OAuthAccessTokenHolder.getInstance();
    79         holder.setAccessToken(getAccessToken());
     94        holder.setAccessToken(apiUrl, getAccessToken());
    8095        holder.setSaveToPreferences(isSaveAccessTokenToPreferences());
     96    }
     97
     98    /**
     99     * Perform the oauth dance
     100     * @param startRemoteControl {@code true} to start remote control if it is not already running
     101     * @param callback The callback to use to notify that the OAuth dance succeeded
     102     * @param apiUrl The API URL to get the token for
     103     * @param oAuthVersion The OAuth version that the authorization dance is force
     104     */
     105    static void authorize(boolean startRemoteControl, Consumer<Optional<IOAuthToken>> callback, String apiUrl, OAuthVersion oAuthVersion) {
     106        final boolean remoteControlIsRunning = Boolean.TRUE.equals(RemoteControl.PROP_REMOTECONTROL_ENABLED.get());
     107        // TODO: Ask user if they want to start remote control?
     108        if (!remoteControlIsRunning && startRemoteControl) {
     109            RemoteControl.start();
     110        }
     111        new OAuth20Authorization().authorize(OAuthParameters.createDefault(apiUrl, oAuthVersion), token -> {
     112                    if (!remoteControlIsRunning) {
     113                        RemoteControl.stop();
     114                    }
     115                    OAuthAccessTokenHolder.getInstance().setAccessToken(apiUrl, token.orElse(null));
     116                    OAuthAccessTokenHolder.getInstance().save(CredentialsManager.getInstance());
     117                    if (!token.isPresent()) {
     118                        GuiHelper.runInEDT(() -> JOptionPane.showMessageDialog(MainApplication.getMainPanel(),
     119                                tr("Authentication failed, please check browser for details."),
     120                                tr("OAuth Authentication Failed"),
     121                                JOptionPane.ERROR_MESSAGE));
     122                    }
     123                    if (callback != null) {
     124                        callback.accept(token);
     125                    }
     126                }, OsmScopes.read_gpx, OsmScopes.write_gpx,
     127                OsmScopes.read_prefs, OsmScopes.write_prefs,
     128                OsmScopes.write_api, OsmScopes.write_notes);
    81129    }
    82130
     
    91139        AcceptAccessTokenAction actAcceptAccessToken = new AcceptAccessTokenAction();
    92140        pnlFullyAutomaticAuthorisationUI.addPropertyChangeListener(actAcceptAccessToken);
    93         pnlSemiAutomaticAuthorisationUI.addPropertyChangeListener(actAcceptAccessToken);
    94141        pnlManualAuthorisationUI.addPropertyChangeListener(actAcceptAccessToken);
    95142
     
    154201            pnlFullyAutomaticAuthorisationUI.revalidate();
    155202            break;
    156         case SEMI_AUTOMATIC:
    157             spAuthorisationProcedureUI.getViewport().setView(pnlSemiAutomaticAuthorisationUI);
    158             pnlSemiAutomaticAuthorisationUI.revalidate();
    159             break;
    160203        case MANUALLY:
    161204            spAuthorisationProcedureUI.getViewport().setView(pnlManualAuthorisationUI);
    162205            pnlManualAuthorisationUI.revalidate();
    163206            break;
     207        default:
     208            throw new UnsupportedOperationException("Unsupported auth type: " + procedure);
    164209        }
    165210        validate();
     
    177222        this.setMinimumSize(new Dimension(500, 300));
    178223
    179         pnlFullyAutomaticAuthorisationUI = new FullyAutomaticAuthorizationUI(apiUrl, executor);
    180         pnlSemiAutomaticAuthorisationUI = new SemiAutomaticAuthorizationUI(apiUrl, executor);
    181         pnlManualAuthorisationUI = new ManualAuthorizationUI(apiUrl, executor);
     224        pnlFullyAutomaticAuthorisationUI = new FullyAutomaticAuthorizationUI(apiUrl, executor, oAuthVersion);
     225        pnlManualAuthorisationUI = new ManualAuthorizationUI(apiUrl, executor, oAuthVersion);
    182226
    183227        spAuthorisationProcedureUI = GuiHelper.embedInVerticalScrollPane(new JPanel());
     
    213257     * @param apiUrl the API URL. Must not be null.
    214258     * @param executor the executor used for running the HTTP requests for the authorization
     259     * @param oAuthVersion The OAuth version this wizard is for
    215260     * @throws IllegalArgumentException if apiUrl is null
    216261     */
    217     public OAuthAuthorizationWizard(Component parent, AuthorizationProcedure procedure, String apiUrl, Executor executor) {
     262    public OAuthAuthorizationWizard(Component parent, AuthorizationProcedure procedure, String apiUrl,
     263                                    Executor executor, OAuthVersion oAuthVersion) {
    218264        super(GuiHelper.getFrameForComponent(parent), ModalityType.DOCUMENT_MODAL);
    219265        this.procedure = Objects.requireNonNull(procedure, "procedure");
    220266        this.apiUrl = Objects.requireNonNull(apiUrl, "apiUrl");
    221267        this.executor = executor;
     268        this.oAuthVersion = oAuthVersion;
    222269        build();
    223270    }
     
    236283        case FULLY_AUTOMATIC: return pnlFullyAutomaticAuthorisationUI;
    237284        case MANUALLY: return pnlManualAuthorisationUI;
    238         case SEMI_AUTOMATIC: return pnlSemiAutomaticAuthorisationUI;
    239285        default: return null;
    240286        }
     
    246292     * @return the access token. May be null if the wizard was canceled.
    247293     */
    248     public OAuthToken getAccessToken() {
     294    public IOAuthToken getAccessToken() {
    249295        return getCurrentAuthorisationUI().getAccessToken();
    250296    }
     
    255301     * @return the current OAuth parameters.
    256302     */
    257     public OAuthParameters getOAuthParameters() {
    258         return (OAuthParameters) getCurrentAuthorisationUI().getOAuthParameters();
     303    public IOAuthParameters getOAuthParameters() {
     304        return getCurrentAuthorisationUI().getOAuthParameters();
    259305    }
    260306
     
    276322    public void initFromPreferences() {
    277323        pnlFullyAutomaticAuthorisationUI.initialize(apiUrl);
    278         pnlSemiAutomaticAuthorisationUI.initialize(apiUrl);
    279324        pnlManualAuthorisationUI.initialize(apiUrl);
    280325    }
     
    316361                    MainApplication.getMainFrame(),
    317362                    AuthorizationProcedure.FULLY_AUTOMATIC,
    318                     serverUrl.toExternalForm(), Utils.newDirectExecutor());
    319             wizard.showDialog();
     363                    serverUrl.toString(), Utils.newDirectExecutor(),
     364                    OAuthVersion.OAuth20);
     365            wizard.showDialog(null);
    320366            return wizard;
    321367        });
     
    368414        }
    369415
    370         public final void updateEnabledState(OAuthToken token) {
     416        /**
     417         * Update the enabled state
     418         * @param token The token to use
     419         * @since 18991
     420         */
     421        public final void updateEnabledState(IOAuthToken token) {
    371422            setEnabled(token != null);
    372423        }
     
    376427            if (!evt.getPropertyName().equals(AbstractAuthorizationUI.ACCESS_TOKEN_PROP))
    377428                return;
    378             updateEnabledState((OAuthToken) evt.getNewValue());
     429            updateEnabledState((IOAuthToken) evt.getNewValue());
    379430        }
    380431    }
  • trunk/src/org/openstreetmap/josm/gui/oauth/TestAccessTokenTask.java

    r18918 r18991  
    1212import javax.xml.parsers.ParserConfigurationException;
    1313
    14 import org.openstreetmap.josm.data.oauth.IOAuthParameters;
    1514import org.openstreetmap.josm.data.oauth.IOAuthToken;
    1615import org.openstreetmap.josm.data.oauth.OAuth20Token;
    17 import org.openstreetmap.josm.data.oauth.OAuthParameters;
    18 import org.openstreetmap.josm.data.oauth.OAuthToken;
     16import org.openstreetmap.josm.data.oauth.OAuthException;
    1917import org.openstreetmap.josm.data.osm.UserInfo;
    2018import org.openstreetmap.josm.gui.HelpAwareOptionPane;
     
    3432import org.xml.sax.SAXException;
    3533
    36 import oauth.signpost.OAuthConsumer;
    37 import oauth.signpost.exception.OAuthException;
    38 
    3934/**
    4035 * Checks whether an OSM API server can be accessed with a specific Access Token.
    41  *
     36 * <p>
    4237 * It retrieves the user details for the user which is authorized to access the server with
    4338 * this token.
     
    4540 */
    4641public class TestAccessTokenTask extends PleaseWaitRunnable {
    47     private final OAuthToken tokenOAuth1;
    4842    private final IOAuthToken tokenOAuth2;
    49     private final IOAuthParameters oauthParameters;
    5043    private boolean canceled;
    5144    private final Component parent;
     
    5851     * @param parent the parent component relative to which the  {@link PleaseWaitRunnable}-Dialog is displayed
    5952     * @param apiUrl the API URL. Must not be null.
    60      * @param parameters the OAuth parameters. Must not be null.
    6153     * @param accessToken the Access Token. Must not be null.
     54     * @since 18991
    6255     */
    63     public TestAccessTokenTask(Component parent, String apiUrl, OAuthParameters parameters, OAuthToken accessToken) {
     56    public TestAccessTokenTask(Component parent, String apiUrl, IOAuthToken accessToken) {
    6457        super(parent, tr("Testing OAuth Access Token"), false /* don't ignore exceptions */);
    6558        CheckParameterUtil.ensureParameterNotNull(apiUrl, "apiUrl");
    66         CheckParameterUtil.ensureParameterNotNull(parameters, "parameters");
    6759        CheckParameterUtil.ensureParameterNotNull(accessToken, "accessToken");
    68         this.tokenOAuth1 = accessToken;
    69         this.tokenOAuth2 = null;
    70         this.oauthParameters = parameters;
    71         this.parent = parent;
    72         this.apiUrl = apiUrl;
    73     }
    74 
    75     /**
    76      * Create the task
    77      *
    78      * @param parent the parent component relative to which the  {@link PleaseWaitRunnable}-Dialog is displayed
    79      * @param apiUrl the API URL. Must not be null.
    80      * @param parameters the OAuth parameters. Must not be null.
    81      * @param accessToken the Access Token. Must not be null.
    82      * @since 18764
    83      */
    84     public TestAccessTokenTask(Component parent, String apiUrl, IOAuthParameters parameters, IOAuthToken accessToken) {
    85         super(parent, tr("Testing OAuth Access Token"), false /* don't ignore exceptions */);
    86         CheckParameterUtil.ensureParameterNotNull(apiUrl, "apiUrl");
    87         CheckParameterUtil.ensureParameterNotNull(parameters, "parameters");
    88         CheckParameterUtil.ensureParameterNotNull(accessToken, "accessToken");
    89         this.tokenOAuth1 = null;
    9060        this.tokenOAuth2 = accessToken;
    91         this.oauthParameters = parameters;
    9261        this.parent = parent;
    9362        this.apiUrl = apiUrl;
     
    11079
    11180    protected void sign(HttpClient con) throws OAuthException {
    112         if (oauthParameters instanceof OAuthParameters) {
    113             OAuthConsumer consumer = ((OAuthParameters) oauthParameters).buildConsumer();
    114             consumer.setTokenWithSecret(tokenOAuth1.getKey(), tokenOAuth1.getSecret());
    115             consumer.sign(con);
    116         } else {
    117             try {
    118                 this.tokenOAuth2.sign(con);
    119             } catch (org.openstreetmap.josm.data.oauth.OAuthException e) {
    120                 // Adapt our OAuthException to the SignPost OAuth exception
    121                 throw new OAuthException(e) {};
    122             }
    123         }
     81        this.tokenOAuth2.sign(con);
    12482    }
    12583
     
    315273
    316274    private String getAuthKey() {
    317         if (this.tokenOAuth1 != null) {
    318             return this.tokenOAuth1.getKey();
    319         }
    320275        if (this.tokenOAuth2 instanceof OAuth20Token) {
    321276            return ((OAuth20Token) this.tokenOAuth2).getBearerToken();
    322277        }
    323         throw new IllegalArgumentException("Only OAuth1 and OAuth2 tokens are understood: " + this.tokenOAuth2);
     278        throw new IllegalArgumentException("Only OAuth2 tokens are understood: " + this.tokenOAuth2);
    324279    }
    325280}
  • trunk/src/org/openstreetmap/josm/gui/preferences/server/AuthenticationPreferencesPanel.java

    r18828 r18991  
    3939    /** indicates whether we use basic authentication */
    4040    private final JRadioButton rbBasicAuthentication = new JRadioButton();
    41     /** indicates whether we use OAuth 1.0a as authentication scheme */
    42     private final JRadioButton rbOAuth = new JRadioButton();
    4341    /** indicates whether we use OAuth 2.0 as authentication scheme */
    4442    private final JRadioButton rbOAuth20 = new JRadioButton();
     
    4745    /** the panel for the basic authentication parameters */
    4846    private BasicAuthenticationPreferencesPanel pnlBasicAuthPreferences;
    49     /** the panel for the OAuth 1.0a authentication parameters */
    50     private OAuthAuthenticationPreferencesPanel pnlOAuthPreferences;
    5147    /** the panel for the OAuth 2.0 authentication parameters */
    5248    private OAuthAuthenticationPreferencesPanel pnlOAuth20Preferences;
     
    5955        final boolean defaultApi = JosmUrls.getInstance().getDefaultOsmApiUrl().equals(apiUrl);
    6056        rbBasicAuthentication.setEnabled(rbBasicAuthentication.isSelected() || "basic".equals(authMethod) || isExpert || !defaultApi);
    61         rbOAuth.setEnabled(rbOAuth.isSelected() || "oauth".equals(authMethod) || isExpert || !defaultApi);
    6257    };
    6358
     
    8580        rbBasicAuthentication.setToolTipText(tr("Select to use HTTP basic authentication with your OSM username and password"));
    8681        rbBasicAuthentication.addItemListener(authChangeListener);
    87 
    88         //-- radio button for OAuth 1.0a
    89         buttonPanel.add(rbOAuth);
    90         rbOAuth.setText(tr("Use OAuth {0}", "1.0a"));
    91         rbOAuth.setToolTipText(tr("Select to use OAuth {0} as authentication mechanism", "1.0a"));
    92         rbOAuth.addItemListener(authChangeListener);
    93 
    9482        //-- radio button for OAuth 2.0
    9583        buttonPanel.add(rbOAuth20);
     84        rbOAuth20.setSelected(true); // This must before adding the listener; otherwise, saveToPreferences is called prior to initFromPreferences
    9685        rbOAuth20.setText(tr("Use OAuth {0}", "2.0"));
    9786        rbOAuth20.setToolTipText(tr("Select to use OAuth {0} as authentication mechanism", "2.0"));
     
    10291        ButtonGroup bg = new ButtonGroup();
    10392        bg.add(rbBasicAuthentication);
    104         bg.add(rbOAuth);
    10593        bg.add(rbOAuth20);
    10694
     
    119107        //-- the two panels for authentication parameters
    120108        pnlBasicAuthPreferences = new BasicAuthenticationPreferencesPanel();
    121         pnlOAuthPreferences = new OAuthAuthenticationPreferencesPanel(OAuthVersion.OAuth10a);
    122109        pnlOAuth20Preferences = new OAuthAuthenticationPreferencesPanel(OAuthVersion.OAuth20);
    123110
    124111        ExpertToggleAction.addExpertModeChangeListener(expertModeChangeListener, true);
    125112
    126         rbOAuth20.setSelected(true);
    127113        pnlAuthenticationParameters.add(pnlOAuth20Preferences, BorderLayout.CENTER);
    128114    }
     
    133119    public final void initFromPreferences() {
    134120        final String authMethod = OsmApi.getAuthMethod();
    135         switch (authMethod) {
    136             case "basic":
    137                 rbBasicAuthentication.setSelected(true);
    138                 break;
    139             case "oauth":
    140                 rbOAuth.setSelected(true);
    141                 break;
    142             case "oauth20":
    143                 rbOAuth20.setSelected(true);
    144                 break;
    145             default:
    146                 Logging.warn(tr("Unsupported value in preference ''{0}'', got ''{1}''. Using authentication method ''Basic Authentication''.",
    147                         "osm-server.auth-method", authMethod));
    148                 rbBasicAuthentication.setSelected(true);
     121        if ("basic".equals(authMethod)) {
     122            rbBasicAuthentication.setSelected(true);
     123        } else if ("oauth20".equals(authMethod)) {
     124            rbOAuth20.setSelected(true);
     125        } else {
     126            Logging.warn(
     127                    tr("Unsupported value in preference ''{0}'', got ''{1}''. Using authentication method ''OAuth 2.0 Authentication''.",
     128                            "osm-server.auth-method", authMethod));
     129            rbOAuth20.setSelected(true);
    149130        }
    150131        pnlBasicAuthPreferences.initFromPreferences();
    151         pnlOAuthPreferences.initFromPreferences();
    152132        pnlOAuth20Preferences.initFromPreferences();
    153133    }
     
    161141        if (rbBasicAuthentication.isSelected()) {
    162142            authMethod = "basic";
    163         } else if (rbOAuth.isSelected()) {
    164             authMethod = "oauth";
    165143        } else if (rbOAuth20.isSelected()) {
    166144            authMethod = "oauth20";
     
    174152            OAuthAccessTokenHolder.getInstance().clear();
    175153            OAuthAccessTokenHolder.getInstance().save(CredentialsManager.getInstance());
    176         } else if ("oauth".equals(authMethod)) {
     154        } else if ("oauth20".equals(authMethod)) {
     155            // oauth20
    177156            // clear the password in the preferences
    178157            pnlBasicAuthPreferences.clearPassword();
    179             pnlBasicAuthPreferences.saveToPreferences();
    180             pnlOAuthPreferences.saveToPreferences();
    181         } else { // oauth20
    182             // clear the password in the preferences
    183             pnlBasicAuthPreferences.clearPassword();
    184             pnlBasicAuthPreferences.saveToPreferences();
    185158            pnlOAuth20Preferences.saveToPreferences();
    186159        }
     
    188161            if ("basic".equals(authMethod)) {
    189162                UserIdentityManager.getInstance().initFromPreferences();
     163            } else if (OsmApi.isUsingOAuthAndOAuthSetUp(OsmApi.getOsmApi())) {
     164                UserIdentityManager.getInstance().initFromOAuth();
    190165            } else {
    191                 UserIdentityManager.getInstance().initFromOAuth();
     166                UserIdentityManager.getInstance().setAnonymous();
    192167            }
    193168        }
     
    205180                pnlAuthenticationParameters.add(pnlBasicAuthPreferences, BorderLayout.CENTER);
    206181                pnlBasicAuthPreferences.revalidate();
    207             } else if (rbOAuth.isSelected()) {
    208                 pnlAuthenticationParameters.add(pnlOAuthPreferences, BorderLayout.CENTER);
    209                 pnlOAuthPreferences.saveToPreferences();
    210                 pnlOAuthPreferences.initFromPreferences();
    211                 pnlOAuthPreferences.revalidate();
    212182            } else if (rbOAuth20.isSelected()) {
    213183                pnlAuthenticationParameters.add(pnlOAuth20Preferences, BorderLayout.CENTER);
     
    222192    @Override
    223193    public void propertyChange(PropertyChangeEvent evt) {
    224         if (pnlOAuthPreferences != null) {
    225             pnlOAuthPreferences.propertyChange(evt);
    226         }
    227194        if (pnlOAuth20Preferences != null) {
    228195            pnlOAuth20Preferences.propertyChange(evt);
  • trunk/src/org/openstreetmap/josm/gui/preferences/server/OAuthAuthenticationPreferencesPanel.java

    r18786 r18991  
    66import java.awt.BorderLayout;
    77import java.awt.Color;
     8import java.awt.Component;
    89import java.awt.FlowLayout;
    910import java.awt.Font;
     
    1516import java.beans.PropertyChangeEvent;
    1617import java.beans.PropertyChangeListener;
     18import java.net.URI;
     19import java.util.Arrays;
     20import java.util.Objects;
    1721
    1822import javax.swing.AbstractAction;
     
    2125import javax.swing.JCheckBox;
    2226import javax.swing.JLabel;
    23 import javax.swing.JOptionPane;
    2427import javax.swing.JPanel;
    2528
    2629import org.openstreetmap.josm.actions.ExpertToggleAction;
    2730import org.openstreetmap.josm.data.oauth.IOAuthToken;
    28 import org.openstreetmap.josm.data.oauth.OAuth20Authorization;
    2931import org.openstreetmap.josm.data.oauth.OAuth20Token;
    3032import org.openstreetmap.josm.data.oauth.OAuthAccessTokenHolder;
    3133import org.openstreetmap.josm.data.oauth.OAuthParameters;
    32 import org.openstreetmap.josm.data.oauth.OAuthToken;
    3334import org.openstreetmap.josm.data.oauth.OAuthVersion;
    34 import org.openstreetmap.josm.data.oauth.osm.OsmScopes;
     35import org.openstreetmap.josm.data.validation.routines.DomainValidator;
    3536import org.openstreetmap.josm.gui.MainApplication;
    3637import org.openstreetmap.josm.gui.oauth.AdvancedOAuthPropertiesPanel;
     
    4344import org.openstreetmap.josm.io.OsmApi;
    4445import org.openstreetmap.josm.io.auth.CredentialsManager;
    45 import org.openstreetmap.josm.io.remotecontrol.RemoteControl;
    4646import org.openstreetmap.josm.tools.GBC;
    4747import org.openstreetmap.josm.tools.ImageProvider;
    4848import org.openstreetmap.josm.tools.Logging;
    4949import org.openstreetmap.josm.tools.UserCancelException;
     50import org.openstreetmap.josm.tools.Utils;
    5051
    5152/**
     
    6970
    7071    /**
    71      * Create the panel. Uses {@link OAuthVersion#OAuth10a}.
    72      */
    73     public OAuthAuthenticationPreferencesPanel() {
    74         this(OAuthVersion.OAuth10a);
    75     }
    76 
    77     /**
    7872     * Create the panel.
    7973     * @param oAuthVersion The OAuth version to use
     
    8276        this.oAuthVersion = oAuthVersion;
    8377        // These must come after we set the oauth version
     78        this.pnlAdvancedProperties = new AdvancedOAuthPropertiesPanel(this.oAuthVersion);
    8479        this.pnlNotYetAuthorised = new NotYetAuthorisedPanel();
    85         this.pnlAdvancedProperties = new AdvancedOAuthPropertiesPanel(this.oAuthVersion);
    8680        this.pnlAlreadyAuthorised = new AlreadyAuthorisedPanel();
    8781        build();
     
    124118        setLayout(new GridBagLayout());
    125119        setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
    126         GridBagConstraints gc = new GridBagConstraints();
    127 
    128120        // the panel for the OAuth parameters. pnlAuthorisationMessage is an
    129121        // empty panel. It is going to be filled later, depending on the
    130122        // current OAuth state in JOSM.
    131         gc.fill = GridBagConstraints.BOTH;
    132         gc.anchor = GridBagConstraints.NORTHWEST;
    133         gc.weighty = 1.0;
    134         gc.weightx = 1.0;
    135         gc.insets = new Insets(10, 0, 0, 0);
    136         add(pnlAuthorisationMessage, gc);
     123        add(pnlAuthorisationMessage, GBC.eol().fill(GridBagConstraints.BOTH).anchor(GridBagConstraints.NORTHWEST)
     124                .weight(1, 1).insets(0, 10, 0, 0));
     125        // the panel with the advanced options
     126        add(buildAdvancedPropertiesPanel(), GBC.eol().fill(GridBagConstraints.HORIZONTAL));
    137127    }
    138128
    139129    protected void refreshView() {
    140130        pnlAuthorisationMessage.removeAll();
    141         if ((this.oAuthVersion == OAuthVersion.OAuth10a &&
    142                 OAuthAccessTokenHolder.getInstance().containsAccessToken())
    143         || OAuthAccessTokenHolder.getInstance().getAccessToken(this.apiUrl, this.oAuthVersion) != null) {
     131        if (OAuthAccessTokenHolder.getInstance().getAccessToken(this.apiUrl, this.oAuthVersion) != null) {
    144132            pnlAuthorisationMessage.add(pnlAlreadyAuthorised, BorderLayout.CENTER);
    145133            pnlAlreadyAuthorised.refreshView();
     
    160148        this.apiUrl = apiUrl;
    161149        pnlAdvancedProperties.setApiUrl(apiUrl);
     150        for (JPanel panel : Arrays.asList(this.pnlNotYetAuthorised, (JPanel) this.pnlAlreadyAuthorised.getComponent(6))) {
     151            for (Component component : panel.getComponents()) {
     152                if (component instanceof JButton && ((JButton) component).getAction() instanceof AuthoriseNowAction) {
     153                    ((AuthoriseNowAction) ((JButton) component).getAction()).updateEnabledState();
     154                }
     155            }
     156        }
    162157    }
    163158
     
    204199
    205200            // Action for authorising now
    206             if (oAuthVersion == OAuthVersion.OAuth10a) {
    207                 add(new JButton(new AuthoriseNowAction(AuthorizationProcedure.FULLY_AUTOMATIC)), GBC.eol());
    208             }
    209             add(new JButton(new AuthoriseNowAction(AuthorizationProcedure.SEMI_AUTOMATIC)), GBC.eol());
    210             if (oAuthVersion == OAuthVersion.OAuth10a) {
    211                 JButton authManually = new JButton(new AuthoriseNowAction(AuthorizationProcedure.MANUALLY));
    212                 add(authManually, GBC.eol());
    213                 ExpertToggleAction.addVisibilitySwitcher(authManually);
    214             }
     201            add(new JButton(new AuthoriseNowAction(AuthorizationProcedure.FULLY_AUTOMATIC)), GBC.eol());
     202            JButton authManually = new JButton(new AuthoriseNowAction(AuthorizationProcedure.MANUALLY));
     203            add(authManually, GBC.eol());
     204            ExpertToggleAction.addVisibilitySwitcher(authManually);
    215205
    216206            // filler - grab remaining space
     
    225215    private class AlreadyAuthorisedPanel extends JPanel {
    226216        private final JosmTextField tfAccessTokenKey = new JosmTextField(null, null, 0, false);
    227         private final JosmTextField tfAccessTokenSecret = new JosmTextField(null, null, 0, false);
    228217
    229218        /**
     
    266255            add(new JLabel(tr("Access Token Secret:")), gc);
    267256
    268             gc.gridx = 1;
    269             gc.weightx = 1.0;
    270             add(tfAccessTokenSecret, gc);
    271             tfAccessTokenSecret.setEditable(false);
    272 
    273257            // -- access token secret
    274258            gc.gridy = 3;
     
    281265            // -- action buttons
    282266            JPanel btns = new JPanel(new FlowLayout(FlowLayout.LEFT));
    283             if (oAuthVersion == OAuthVersion.OAuth10a) {
    284                 // these want the OAuth 1.0 token information
    285                 btns.add(new JButton(new RenewAuthorisationAction(AuthorizationProcedure.FULLY_AUTOMATIC)));
    286             }
    287             btns.add(new JButton(new TestAuthorisationAction(oAuthVersion)));
     267            btns.add(new JButton(new RenewAuthorisationAction(AuthorizationProcedure.FULLY_AUTOMATIC)));
     268            btns.add(new JButton(new TestAuthorisationAction()));
    288269            btns.add(new JButton(new RemoveAuthorisationAction()));
    289270            gc.gridy = 4;
     
    293274            add(btns, gc);
    294275
    295             // the panel with the advanced options
    296             gc.gridy = 5;
    297             gc.gridx = 0;
    298             gc.gridwidth = 2;
    299             gc.weightx = 1.0;
    300             add(buildAdvancedPropertiesPanel(), gc);
    301 
    302276            // filler - grab the remaining space
    303277            gc.gridy = 6;
     
    310284        protected final void refreshView() {
    311285            switch (oAuthVersion) {
    312                 case OAuth10a:
    313                     String v = OAuthAccessTokenHolder.getInstance().getAccessTokenKey();
    314                     tfAccessTokenKey.setText(v == null ? "" : v);
    315                     v = OAuthAccessTokenHolder.getInstance().getAccessTokenSecret();
    316                     tfAccessTokenSecret.setText(v == null ? "" : v);
    317                     tfAccessTokenSecret.setVisible(true);
    318                     break;
    319286                case OAuth20:
    320287                case OAuth21:
     
    325292                    }
    326293                    tfAccessTokenKey.setText(token == null ? "" : token);
    327                     tfAccessTokenSecret.setVisible(false);
     294                    break;
     295                default:
    328296            }
    329297            cbSaveToPreferences.setSelected(OAuthAccessTokenHolder.getInstance().isSaveToPreferences());
     
    341309            putValue(NAME, tr("{0} ({1})", tr("Authorize now"), procedure.getText()));
    342310            putValue(SHORT_DESCRIPTION, procedure.getDescription());
    343             if (procedure == AuthorizationProcedure.FULLY_AUTOMATIC
    344             || OAuthAuthenticationPreferencesPanel.this.oAuthVersion != OAuthVersion.OAuth10a) {
     311            if (procedure == AuthorizationProcedure.FULLY_AUTOMATIC) {
    345312                new ImageProvider("oauth", "oauth-small").getResource().attachImageIcon(this);
    346313            }
     314            updateEnabledState();
     315        }
     316
     317        void updateEnabledState() {
     318            if (procedure == AuthorizationProcedure.MANUALLY) {
     319                this.setEnabled(true);
     320            } else if (Utils.isValidUrl(apiUrl) && DomainValidator.getInstance().isValid(URI.create(apiUrl).getHost())) {
     321                // We want to avoid trying to make connection with an invalid URL
     322                final String currentApiUrl = apiUrl;
     323                MainApplication.worker.execute(() -> {
     324                    final String clientId = OAuthParameters.createDefault(apiUrl, oAuthVersion).getClientId();
     325                    if (Objects.equals(apiUrl, currentApiUrl)) {
     326                        GuiHelper.runInEDT(() -> this.setEnabled(!Utils.isEmpty(clientId)));
     327                    }
     328                });
     329            }
    347330        }
    348331
    349332        @Override
    350333        public void actionPerformed(ActionEvent arg0) {
    351             if (OAuthAuthenticationPreferencesPanel.this.oAuthVersion == OAuthVersion.OAuth10a) {
    352                 OAuthAuthorizationWizard wizard = new OAuthAuthorizationWizard(
    353                         OAuthAuthenticationPreferencesPanel.this,
    354                         procedure,
    355                         apiUrl,
    356                         MainApplication.worker);
    357                 try {
    358                     wizard.showDialog();
    359                 } catch (UserCancelException ignore) {
    360                     Logging.trace(ignore);
    361                     return;
    362                 }
    363                 pnlAdvancedProperties.setAdvancedParameters(wizard.getOAuthParameters());
    364                 refreshView();
    365             } else {
    366                 final boolean remoteControlIsRunning = Boolean.TRUE.equals(RemoteControl.PROP_REMOTECONTROL_ENABLED.get());
    367                 // TODO: Ask user if they want to start remote control?
    368                 if (!remoteControlIsRunning) {
    369                     RemoteControl.start();
    370                 }
    371                 new OAuth20Authorization().authorize(OAuthParameters.createDefault(OsmApi.getOsmApi().getServerUrl(), oAuthVersion), token -> {
    372                     if (!remoteControlIsRunning) {
    373                         RemoteControl.stop();
    374                     }
    375                     OAuthAccessTokenHolder.getInstance().setAccessToken(OsmApi.getOsmApi().getServerUrl(), token.orElse(null));
    376                     OAuthAccessTokenHolder.getInstance().save(CredentialsManager.getInstance());
    377                     GuiHelper.runInEDT(OAuthAuthenticationPreferencesPanel.this::refreshView);
    378                     if (!token.isPresent()) {
    379                         GuiHelper.runInEDT(() -> JOptionPane.showMessageDialog(MainApplication.getMainPanel(),
    380                                 tr("Authentication failed, please check browser for details."),
    381                                 tr("OAuth Authentication Failed"),
    382                                 JOptionPane.ERROR_MESSAGE));
    383                     }
    384                 }, OsmScopes.read_gpx, OsmScopes.write_gpx,
    385                         OsmScopes.read_prefs, OsmScopes.write_prefs,
    386                         OsmScopes.write_api, OsmScopes.write_notes);
     334            OAuthAuthorizationWizard wizard = new OAuthAuthorizationWizard(
     335                    OAuthAuthenticationPreferencesPanel.this,
     336                    procedure,
     337                    apiUrl,
     338                    MainApplication.worker,
     339                    oAuthVersion);
     340            try {
     341                wizard.showDialog(token -> GuiHelper.runInEDT(OAuthAuthenticationPreferencesPanel.this::refreshView));
     342            } catch (UserCancelException userCancelException) {
     343                Logging.trace(userCancelException);
     344                return;
    387345            }
     346            pnlAdvancedProperties.setAdvancedParameters(wizard.getOAuthParameters());
     347            refreshView();
    388348        }
    389349    }
     
    401361        @Override
    402362        public void actionPerformed(ActionEvent e) {
    403             if (oAuthVersion == OAuthVersion.OAuth10a) {
    404                 OAuthAccessTokenHolder.getInstance().setAccessToken(null);
    405             } else {
    406                 OAuthAccessTokenHolder.getInstance().setAccessToken(apiUrl, (IOAuthToken) null);
    407             }
     363            OAuthAccessTokenHolder.getInstance().setAccessToken(apiUrl, null);
    408364            OAuthAccessTokenHolder.getInstance().save(CredentialsManager.getInstance());
    409365            refreshView();
     
    430386     */
    431387    private class TestAuthorisationAction extends AbstractAction {
    432         private final OAuthVersion oAuthVersion;
    433 
    434388        /**
    435389         * Constructs a new {@code TestAuthorisationAction}.
    436390         */
    437         TestAuthorisationAction(OAuthVersion oAuthVersion) {
    438             this.oAuthVersion = oAuthVersion;
     391        TestAuthorisationAction() {
    439392            putValue(NAME, tr("Test Access Token"));
    440393            putValue(SHORT_DESCRIPTION, tr("Click test access to the OSM server with the current access token"));
     
    444397        @Override
    445398        public void actionPerformed(ActionEvent evt) {
    446             if (this.oAuthVersion == OAuthVersion.OAuth10a) {
    447                 OAuthToken token = OAuthAccessTokenHolder.getInstance().getAccessToken();
    448                 OAuthParameters parameters = OAuthParameters.createFromApiUrl(OsmApi.getOsmApi().getServerUrl());
    449                 TestAccessTokenTask task = new TestAccessTokenTask(
    450                         OAuthAuthenticationPreferencesPanel.this,
    451                         apiUrl,
    452                         parameters,
    453                         token
    454                 );
    455                 MainApplication.worker.submit(task);
    456             } else {
    457                 IOAuthToken token = OAuthAccessTokenHolder.getInstance().getAccessToken(OsmApi.getOsmApi().getBaseUrl(), OAuthVersion.OAuth20);
    458                 TestAccessTokenTask task = new TestAccessTokenTask(
    459                         OAuthAuthenticationPreferencesPanel.this,
    460                         apiUrl,
    461                         token.getParameters(),
    462                         token
    463                 );
    464                 MainApplication.worker.submit(task);
    465             }
     399            IOAuthToken token = OAuthAccessTokenHolder.getInstance().getAccessToken(OsmApi.getOsmApi().getBaseUrl(), OAuthVersion.OAuth20);
     400            TestAccessTokenTask task = new TestAccessTokenTask(
     401                    OAuthAuthenticationPreferencesPanel.this,
     402                    apiUrl,
     403                    token
     404            );
     405            MainApplication.worker.submit(task);
    466406        }
    467407    }
  • trunk/src/org/openstreetmap/josm/io/MessageNotifier.java

    r18650 r18991  
    145145            try {
    146146                if (JosmPreferencesCredentialAgent.class.equals(credManager.getCredentialsAgentClass())) {
    147                     if (OsmApi.isUsingOAuth(OAuthVersion.OAuth10a)) {
    148                         return credManager.lookupOAuthAccessToken() != null;
    149                     } else if (OsmApi.isUsingOAuth(OAuthVersion.OAuth20) || OsmApi.isUsingOAuth(OAuthVersion.OAuth21)) {
     147                    if (OsmApi.isUsingOAuth(OAuthVersion.OAuth20) || OsmApi.isUsingOAuth(OAuthVersion.OAuth21)) {
    150148                        return credManager.lookupOAuthAccessToken(OsmApi.getOsmApi().getHost()) != null;
    151149                    } else if (OsmApi.isUsingOAuth()) {
  • trunk/src/org/openstreetmap/josm/io/OsmApi.java

    r18871 r18991  
    5252import org.xml.sax.SAXParseException;
    5353
     54import jakarta.annotation.Nullable;
     55
    5456/**
    5557 * Class that encapsulates the communications with the <a href="http://wiki.openstreetmap.org/wiki/API_v0.6">OSM API</a>.<br><br>
     
    8587
    8688    private static final ListenerList<OsmApiInitializationListener> listeners = ListenerList.create();
    87     /** This is used to make certain we have set osm-server.auth-method to the "right" default */
    88     private static boolean oauthCompatibilitySwitch;
    8989
    9090    private URL url;
     
    653653     */
    654654    public static boolean isUsingOAuth() {
    655         return isUsingOAuth(OAuthVersion.OAuth10a)
    656                 || isUsingOAuth(OAuthVersion.OAuth20)
     655        return isUsingOAuth(OAuthVersion.OAuth20)
    657656                || isUsingOAuth(OAuthVersion.OAuth21);
    658657    }
     
    665664     */
    666665    public static boolean isUsingOAuth(OAuthVersion version) {
    667         if (version == OAuthVersion.OAuth10a) {
    668             return "oauth".equalsIgnoreCase(getAuthMethod());
    669         } else if (version == OAuthVersion.OAuth20 || version == OAuthVersion.OAuth21) {
    670             return "oauth20".equalsIgnoreCase(getAuthMethod());
     666        if (version == OAuthVersion.OAuth20 || version == OAuthVersion.OAuth21) {
     667            return getAuthMethodVersion() == OAuthVersion.OAuth20 || getAuthMethodVersion() == OAuthVersion.OAuth21;
    671668        }
    672669        return false;
     
    680677    public static boolean isUsingOAuthAndOAuthSetUp(OsmApi api) {
    681678        if (OsmApi.isUsingOAuth()) {
    682             if (OsmApi.isUsingOAuth(OAuthVersion.OAuth10a)) {
    683                 return OAuthAccessTokenHolder.getInstance().containsAccessToken();
    684             }
    685679            if (OsmApi.isUsingOAuth(OAuthVersion.OAuth20)) {
    686680                return OAuthAccessTokenHolder.getInstance().getAccessToken(api.getBaseUrl(), OAuthVersion.OAuth20) != null;
     
    698692     */
    699693    public static String getAuthMethod() {
    700         setCurrentAuthMethod();
    701694        return Config.getPref().get("osm-server.auth-method", "oauth20");
    702695    }
    703696
    704697    /**
    705      * This is a compatibility method for users who currently use OAuth 1.0 -- we are changing the default from oauth to oauth20,
    706      * but since oauth was the default, pre-existing users will suddenly be switched to oauth20.
    707      * This should be removed whenever {@link OAuthVersion#OAuth10a} support is removed.
    708      */
    709     private static void setCurrentAuthMethod() {
    710         if (!oauthCompatibilitySwitch) {
    711             oauthCompatibilitySwitch = true;
    712             final String prefKey = "osm-server.auth-method";
    713             if ("oauth20".equals(Config.getPref().get(prefKey, "oauth20"))
    714                 && !isUsingOAuthAndOAuthSetUp(OsmApi.getOsmApi())
    715                 && OAuthAccessTokenHolder.getInstance().containsAccessToken()) {
    716                 Config.getPref().put(prefKey, "oauth");
    717             }
     698     * Returns the authentication method set in the preferences
     699     * @return the authentication method
     700     * @since 18991
     701     */
     702    @Nullable
     703    public static OAuthVersion getAuthMethodVersion() {
     704        switch (getAuthMethod()) {
     705            case "oauth20": return OAuthVersion.OAuth20;
     706            case "oauth21": return OAuthVersion.OAuth21;
     707            case "basic": return null;
     708            default:
     709                Config.getPref().put("osm-server.auth-method", null);
     710                return getAuthMethodVersion();
    718711        }
    719712    }
  • trunk/src/org/openstreetmap/josm/io/OsmConnection.java

    r18665 r18991  
    66import java.lang.reflect.InvocationTargetException;
    77import java.net.Authenticator.RequestorType;
    8 import java.net.MalformedURLException;
    98import java.net.URL;
    109import java.nio.charset.StandardCharsets;
     
    3635import org.openstreetmap.josm.tools.Logging;
    3736
    38 import oauth.signpost.OAuthConsumer;
    39 import oauth.signpost.exception.OAuthException;
    40 
    4137/**
    4238 * Base class that handles common things like authentication for the reader and writer
     
    5147    protected boolean cancel;
    5248    protected HttpClient activeConnection;
    53     protected OAuthParameters oauthParameters;
    5449    protected IOAuthParameters oAuth20Parameters;
    5550
     
    146141
    147142    /**
    148      * Signs the connection with an OAuth authentication header
    149      *
    150      * @param connection the connection
    151      *
    152      * @throws MissingOAuthAccessTokenException if there is currently no OAuth Access Token configured
    153      * @throws OsmTransferException if signing fails
    154      */
    155     protected void addOAuthAuthorizationHeader(HttpClient connection) throws OsmTransferException {
    156         if (oauthParameters == null) {
    157             oauthParameters = OAuthParameters.createFromApiUrl(OsmApi.getOsmApi().getServerUrl());
    158         }
    159         OAuthConsumer consumer = oauthParameters.buildConsumer();
    160         OAuthAccessTokenHolder holder = OAuthAccessTokenHolder.getInstance();
    161         if (!holder.containsAccessToken()) {
    162             obtainAccessToken(connection);
    163         }
    164         if (!holder.containsAccessToken()) { // check if wizard completed
    165             throw new MissingOAuthAccessTokenException();
    166         }
    167         consumer.setTokenWithSecret(holder.getAccessTokenKey(), holder.getAccessTokenSecret());
    168         try {
    169             consumer.sign(connection);
    170         } catch (OAuthException e) {
    171             throw new OsmTransferException(tr("Failed to sign a HTTP connection with an OAuth Authentication header"), e);
    172         }
    173     }
    174 
    175     /**
    176      * Obtains an OAuth access token for the connection.
    177      * Afterwards, the token is accessible via {@link OAuthAccessTokenHolder} / {@link CredentialsManager}.
    178      * @param connection connection for which the access token should be obtained
    179      * @throws MissingOAuthAccessTokenException if the process cannot be completed successfully
    180      */
    181     protected void obtainAccessToken(final HttpClient connection) throws MissingOAuthAccessTokenException {
    182         try {
    183             final URL apiUrl = new URL(OsmApi.getOsmApi().getServerUrl());
    184             if (!Objects.equals(apiUrl.getHost(), connection.getURL().getHost())) {
    185                 throw new MissingOAuthAccessTokenException();
    186             }
    187             fetcher.obtainAccessToken(apiUrl);
    188             OAuthAccessTokenHolder.getInstance().setSaveToPreferences(true);
    189             OAuthAccessTokenHolder.getInstance().save(CredentialsManager.getInstance());
    190         } catch (MalformedURLException | InvocationTargetException e) {
    191             throw new MissingOAuthAccessTokenException(e);
    192         } catch (InterruptedException e) {
    193             Thread.currentThread().interrupt();
    194             throw new MissingOAuthAccessTokenException(e);
    195         }
    196     }
    197 
    198     /**
    199143     * Obtains an OAuth access token for the connection.
    200144     * Afterwards, the token is accessible via {@link OAuthAccessTokenHolder} / {@link CredentialsManager}.
     
    221165                    }
    222166                    // Clean up old token/password
    223                     OAuthAccessTokenHolder.getInstance().setAccessToken(null);
    224167                    OAuthAccessTokenHolder.getInstance().setAccessToken(OsmApi.getOsmApi().getServerUrl(), authToken.orElse(null));
    225168                    OAuthAccessTokenHolder.getInstance().save(CredentialsManager.getInstance());
     
    281224                addBasicAuthorizationHeader(connection);
    282225                return;
    283             case "oauth":
    284                 addOAuthAuthorizationHeader(connection);
    285                 return;
    286226            case "oauth20":
    287227                addOAuth20AuthorizationHeader(connection);
  • trunk/src/org/openstreetmap/josm/io/auth/CredentialsAgent.java

    r18877 r18991  
    77
    88import org.openstreetmap.josm.data.oauth.IOAuthToken;
    9 import org.openstreetmap.josm.data.oauth.OAuthToken;
    109
    1110import jakarta.annotation.Nullable;
     
    6564     * @return the current OAuth Access Token to access the OSM server.
    6665     * @throws CredentialsAgentException if something goes wrong
     66     * @deprecated since 18991 -- OAuth 1.0 is being removed from the OSM API
    6767     */
    68     OAuthToken lookupOAuthAccessToken() throws CredentialsAgentException;
     68    @Deprecated
     69    default IOAuthToken lookupOAuthAccessToken() throws CredentialsAgentException {
     70        throw new CredentialsAgentException("Call to deprecated method");
     71    }
    6972
    7073    /**
     
    8588     * @param accessToken the access Token. null, to remove the Access Token.
    8689     * @throws CredentialsAgentException if something goes wrong
     90     * @deprecated since 18991 -- OAuth 1.0 is being removed from the OSM API
    8791     */
    88     void storeOAuthAccessToken(OAuthToken accessToken) throws CredentialsAgentException;
     92    @Deprecated
     93    default void storeOAuthAccessToken(IOAuthToken accessToken) throws CredentialsAgentException {
     94        throw new CredentialsAgentException("Call to deprecated method");
     95    }
    8996
    9097    /**
     
    93100     * @param host The host the access token is for
    94101     * @param accessToken the access Token. null, to remove the Access Token. This will remove all IOAuthTokens <i>not</i> managed by
    95      *                    {@link #storeOAuthAccessToken(OAuthToken)}.
     102     *                    {@link #storeOAuthAccessToken(IOAuthToken)}.
    96103     * @throws CredentialsAgentException if something goes wrong
    97104     * @since 18650
  • trunk/src/org/openstreetmap/josm/io/auth/CredentialsManager.java

    r18650 r18991  
    99import org.openstreetmap.josm.data.UserIdentityManager;
    1010import org.openstreetmap.josm.data.oauth.IOAuthToken;
    11 import org.openstreetmap.josm.data.oauth.OAuthToken;
    1211import org.openstreetmap.josm.io.OsmApi;
    1312import org.openstreetmap.josm.tools.CheckParameterUtil;
     
    1716/**
    1817 * CredentialManager is a factory for the single credential agent used.
    19  *
     18 * <p>
    2019 * Currently, it defaults to replying an instance of {@link JosmPreferencesCredentialAgent}.
    2120 * @since 2641
     
    158157
    159158    @Override
    160     public OAuthToken lookupOAuthAccessToken() throws CredentialsAgentException {
    161         return delegate.lookupOAuthAccessToken();
    162     }
    163 
    164     @Override
    165159    public IOAuthToken lookupOAuthAccessToken(String host) throws CredentialsAgentException {
    166160        return delegate.lookupOAuthAccessToken(host);
    167     }
    168 
    169     @Override
    170     public void storeOAuthAccessToken(OAuthToken accessToken) throws CredentialsAgentException {
    171         delegate.storeOAuthAccessToken(accessToken);
    172161    }
    173162
  • trunk/src/org/openstreetmap/josm/io/auth/JosmPreferencesCredentialAgent.java

    r18723 r18991  
    1818import org.openstreetmap.josm.data.oauth.OAuth20Parameters;
    1919import org.openstreetmap.josm.data.oauth.OAuth20Token;
    20 import org.openstreetmap.josm.data.oauth.OAuthToken;
    2120import org.openstreetmap.josm.data.oauth.OAuthVersion;
    2221import org.openstreetmap.josm.gui.widgets.HtmlPanel;
     
    103102    }
    104103
    105     /**
    106      * Lookup the current OAuth Access Token to access the OSM server. Replies null, if no
    107      * Access Token is currently managed by this CredentialManager.
    108      *
    109      * @return the current OAuth Access Token to access the OSM server.
    110      * @throws CredentialsAgentException if something goes wrong
    111      */
    112     @Override
    113     public OAuthToken lookupOAuthAccessToken() throws CredentialsAgentException {
    114         String accessTokenKey = Config.getPref().get("oauth.access-token.key", null);
    115         String accessTokenSecret = Config.getPref().get("oauth.access-token.secret", null);
    116         if (accessTokenKey == null && accessTokenSecret == null)
    117             return null;
    118         return new OAuthToken(accessTokenKey, accessTokenSecret);
    119     }
    120 
    121104    @Override
    122105    public IOAuthToken lookupOAuthAccessToken(String host) throws CredentialsAgentException {
     
    141124        }
    142125        return null;
    143     }
    144 
    145     /**
    146      * Stores the OAuth Access Token <code>accessToken</code>.
    147      *
    148      * @param accessToken the access Token. null, to remove the Access Token.
    149      * @throws CredentialsAgentException if something goes wrong
    150      */
    151     @Override
    152     public void storeOAuthAccessToken(OAuthToken accessToken) throws CredentialsAgentException {
    153         if (accessToken == null) {
    154             Config.getPref().put("oauth.access-token.key", null);
    155             Config.getPref().put("oauth.access-token.secret", null);
    156         } else {
    157             Config.getPref().put("oauth.access-token.key", accessToken.getKey());
    158             Config.getPref().put("oauth.access-token.secret", accessToken.getSecret());
    159         }
    160126    }
    161127
  • trunk/src/org/openstreetmap/josm/tools/ExceptionUtil.java

    r18211 r18991  
    298298                + "Please launch the preferences dialog and retrieve another OAuth token."
    299299                + "</html>",
    300                 OAuthAccessTokenHolder.getInstance().getAccessTokenKey()
     300                OAuthAccessTokenHolder.getInstance().getAccessToken(e.getUrl(), OsmApi.getAuthMethodVersion())
    301301        );
    302302    }
     
    344344                + "Please launch the preferences dialog and retrieve another OAuth token."
    345345                + "</html>",
    346                 OAuthAccessTokenHolder.getInstance().getAccessTokenKey(),
     346                OAuthAccessTokenHolder.getInstance().getAccessToken(e.getUrl(), OsmApi.getAuthMethodVersion()),
    347347                e.getAccessedUrl() == null ? tr("unknown") : e.getAccessedUrl()
    348348        );
Note: See TracChangeset for help on using the changeset viewer.