Changeset 19627 in josm


Ignore:
Timestamp:
2026-09-20T21:33:09+02:00 (40 hours ago)
Author:
stoecker
Message:

fix #24890 - handle OAuth 2 against a server without a built-in client id - fix #24889 - add OAuthID for OpenGeofiction - patches by wangi

Location:
trunk/src/org/openstreetmap/josm
Files:
4 edited

Legend:

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

    r19519 r19627  
    2828import org.openstreetmap.josm.io.remotecontrol.handler.RequestHandler;
    2929import org.openstreetmap.josm.tools.HttpClient;
     30import org.openstreetmap.josm.tools.Utils;
    3031import org.openstreetmap.josm.tools.JosmRuntimeException;
    3132import org.openstreetmap.josm.tools.OpenBrowser;
     
    126127            try {
    127128                HttpClient tradeCodeForToken = HttpClient.create(new URL(parameters.getAccessTokenUrl()), "POST");
     129                // A confidential client (the default when registering an application on
     130                // openstreetmap-website) must present its secret at the token endpoint;
     131                // the built-in OSM application is a public client and has none.
     132                String clientSecret = parameters.getClientSecret();
    128133                tradeCodeForToken.setRequestBody(("grant_type=authorization_code&client_id=" + parameters.getClientId()
     134                        + (!Utils.isEmpty(clientSecret) ? "&client_secret=" + Utils.encodeUrl(clientSecret) : "")
    129135                        + "&redirect_uri=" + parameters.getRedirectUri()
    130136                        + "&code=" + code
     
    135141                    tradeCodeForToken.connect();
    136142                    HttpClient.Response response = tradeCodeForToken.getResponse();
     143                    if (response.getResponseCode() >= 400) {
     144                        // Doorkeeper answers a rejected exchange with a JSON error body, but an
     145                        // authentication failure can come back with none - say what the server said
     146                        String body = response.fetchContent();
     147                        throw new OAuth20Exception(tr("The server refused the token request: HTTP {0} {1}",
     148                                response.getResponseCode(), Utils.isEmpty(body) ? response.getResponseMessage() : body));
     149                    }
    137150                    OAuth20Token oAuth20Token = new OAuth20Token(parameters, response.getContentReader());
    138151                    consumer.accept(Optional.of(oAuth20Token));
  • trunk/src/org/openstreetmap/josm/data/oauth/OAuthParameters.java

    r19253 r19627  
    7777                throw new IllegalArgumentException("Unknown OAuth version: " + oAuthVersion);
    7878        }
     79    }
     80
     81    /**
     82     * Get the OAuth 2.0 parameters the user entered in the advanced OAuth settings and saved with
     83     * {@link IOAuthParameters#rememberPreferences()}. Until a token exists, this is the only place a
     84     * client id for a server not in {@link #createDefault(String, OAuthVersion)} can come from.
     85     * {@link OAuth20Parameters#rememberPreferences()} keys by the API URL as given; callers may pass
     86     * either the URL or its host, so both are tried.
     87     * @param keys The preference key suffixes to try, in order
     88     * @return The remembered parameters, or {@code null} if none are saved or they cannot be parsed
     89     * @since 19627
     90     */
     91    private static IOAuthParameters createFromPreferences(String... keys) {
     92        for (String key : keys) {
     93            if (Utils.isEmpty(key)) {
     94                continue;
     95            }
     96            final String json = Config.getPref().get("oauth.access-token.parameters." + OAuthVersion.OAuth20 + "." + key, null);
     97            if (Utils.isEmpty(json)) {
     98                continue;
     99            }
     100            try {
     101                OAuth20Parameters parameters = new OAuth20Parameters(json);
     102                if (!Utils.isEmpty(parameters.getClientId())) {
     103                    return parameters;
     104                }
     105            } catch (IllegalArgumentException | NullPointerException | JsonParsingException e) {
     106                // A preference written by hand, or by an older JOSM with different fields
     107                Logging.trace(e);
     108            }
     109        }
     110        return null;
    79111    }
    80112
     
    138170                clientSecret = null;
    139171                break;
     172            case "https://opengeofiction.net/api":
     173            case "https://lugus.opengeofiction.net/api":
     174                // clientId provided by wangi (Lee Kindness), OpenGeofiction administrator.
     175                // lugus is the OpenGeofiction test server.
     176                clientId = "dKB9Fb5H4MxrM3I23UFxNCh5VGiAEQ_20gC7WmXnaaY";
     177                clientSecret = null;
     178                break;
    140179            default:
    141180                clientId = "";
     
    200239     */
    201240    public static IOAuthParameters createFromApiUrl(String apiUrl, OAuthVersion oAuthVersion) {
     241        final String originalApiUrl = apiUrl;
    202242        // We actually need the host
    203243        if (apiUrl.startsWith("https://") || apiUrl.startsWith("http://")) {
     
    219259                    Logging.trace(e);
    220260                }
     261                IOAuthParameters remembered = createFromPreferences(originalApiUrl, apiUrl);
     262                if (remembered != null) {
     263                    return remembered;
     264                }
    221265                return createDefault(apiUrl, oAuthVersion);
    222266            default:
  • trunk/src/org/openstreetmap/josm/gui/oauth/AdvancedOAuthPropertiesPanel.java

    r19008 r19627  
    1515import javax.swing.JLabel;
    1616import javax.swing.JOptionPane;
     17import javax.swing.event.DocumentEvent;
     18import javax.swing.event.DocumentListener;
    1719
    1820import org.openstreetmap.josm.data.oauth.IOAuthParameters;
     
    4850 */
    4951public class AdvancedOAuthPropertiesPanel extends VerticallyScrollablePanel {
     52    /**
     53     * Property fired whenever the parameters this panel would return change: the client id was edited,
     54     * or "use default settings" was toggled. Listeners re-read {@link #getAdvancedParameters()}.
     55     * @since 19627
     56     */
     57    public static final String PARAMETERS_CHANGED_PROP = AdvancedOAuthPropertiesPanel.class.getName() + ".parametersChanged";
    5058
    5159    private final JCheckBox cbUseDefaults = new JCheckBox(tr("Use default settings"));
     
    138146        cbUseDefaults.addItemListener(ilUseDefault);
    139147        cbUseDefaults.setSelected(Config.getPref().getBoolean("oauth.settings.use-default", true));
     148        cbUseDefaults.addItemListener(e -> fireParametersChanged());
     149        tfConsumerKey.getDocument().addDocumentListener(new DocumentListener() {
     150            @Override
     151            public void insertUpdate(DocumentEvent e) {
     152                fireParametersChanged();
     153            }
     154
     155            @Override
     156            public void removeUpdate(DocumentEvent e) {
     157                fireParametersChanged();
     158            }
     159
     160            @Override
     161            public void changedUpdate(DocumentEvent e) {
     162                fireParametersChanged();
     163            }
     164        });
     165    }
     166
     167    private void fireParametersChanged() {
     168        firePropertyChange(PARAMETERS_CHANGED_PROP, null, null);
     169    }
     170
     171    /**
     172     * Determines if the panel is set to use the default parameters for the API URL rather than
     173     * the values entered in its fields.
     174     * @return {@code true} if "use default settings" is selected
     175     * @since 19627
     176     */
     177    public boolean isUseDefaultSettings() {
     178        return cbUseDefaults.isSelected();
     179    }
     180
     181    /**
     182     * Get the client id as entered in the panel, without falling back to the defaults.
     183     * @return the client id field's text
     184     * @since 19627
     185     */
     186    public String getEnteredClientId() {
     187        return tfConsumerKey.getText();
    140188    }
    141189
  • trunk/src/org/openstreetmap/josm/gui/preferences/server/OAuthAuthenticationPreferencesPanel.java

    r19008 r19627  
    110110        );
    111111        pnlAdvancedProperties.setVisible(false);
     112        pnlAdvancedProperties.addPropertyChangeListener(this);
    112113        return pnl;
     114    }
     115
     116    /**
     117     * Re-evaluate whether the "Authorize now" buttons can be enabled, after the API URL or the
     118     * advanced OAuth parameters changed.
     119     */
     120    private void updateAuthoriseNowActions() {
     121        for (JPanel panel : Arrays.asList(this.pnlNotYetAuthorised, (JPanel) this.pnlAlreadyAuthorised.getComponent(6))) {
     122            for (Component component : panel.getComponents()) {
     123                if (component instanceof JButton && ((JButton) component).getAction() instanceof AuthoriseNowAction) {
     124                    ((AuthoriseNowAction) ((JButton) component).getAction()).updateEnabledState();
     125                }
     126            }
     127        }
    113128    }
    114129
     
    149164        this.apiUrl = apiUrl;
    150165        pnlAdvancedProperties.setApiUrl(apiUrl);
    151         for (JPanel panel : Arrays.asList(this.pnlNotYetAuthorised, (JPanel) this.pnlAlreadyAuthorised.getComponent(6))) {
    152             for (Component component : panel.getComponents()) {
    153                 if (component instanceof JButton && ((JButton) component).getAction() instanceof AuthoriseNowAction) {
    154                     ((AuthoriseNowAction) ((JButton) component).getAction()).updateEnabledState();
    155                 }
    156             }
    157         }
     166        updateAuthoriseNowActions();
    158167    }
    159168
     
    319328            if (procedure == AuthorizationProcedure.MANUALLY) {
    320329                this.setEnabled(true);
     330            } else if (!pnlAdvancedProperties.isUseDefaultSettings()) {
     331                // The user supplied the parameters - the client id of an OAuth application they
     332                // registered on the server themselves. The wizard is given exactly these parameters
     333                // when the button is pressed, so they decide whether it can be pressed.
     334                this.setEnabled(!Utils.isEmpty(pnlAdvancedProperties.getEnteredClientId()));
    321335            } else if (Utils.isValidUrl(apiUrl)) {
    322336                final URI apiURI;
     
    421435    @Override
    422436    public void propertyChange(PropertyChangeEvent evt) {
    423         if (!evt.getPropertyName().equals(OsmApiUrlInputPanel.API_URL_PROP))
    424             return;
    425         setApiUrl((String) evt.getNewValue());
     437        if (AdvancedOAuthPropertiesPanel.PARAMETERS_CHANGED_PROP.equals(evt.getPropertyName())) {
     438            updateAuthoriseNowActions();
     439        } else if (OsmApiUrlInputPanel.API_URL_PROP.equals(evt.getPropertyName())) {
     440            setApiUrl((String) evt.getNewValue());
     441        }
    426442    }
    427443}
Note: See TracChangeset for help on using the changeset viewer.