mirror of
https://github.com/google/nomulus.git
synced 2025-07-25 12:08:36 +02:00
Remove to-be-deprecated OOB OAuth flow in nomulus login (#1625)
This commit is contained in:
parent
bb27feebd6
commit
17d0080742
2 changed files with 93 additions and 10 deletions
|
@ -0,0 +1,72 @@
|
||||||
|
// Copyright 2022 The Nomulus Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package google.registry.tools;
|
||||||
|
|
||||||
|
import com.google.api.client.extensions.java6.auth.oauth2.VerificationCodeReceiver;
|
||||||
|
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A thin wrapper around {@link LocalServerReceiver} which points the redirect URI to a different
|
||||||
|
* port (the forwarding port) while still listening on the random unused port (the remote port)
|
||||||
|
* nomulus itself picks. This allows us to run the nomulus tool on a remote host (which one can SSH
|
||||||
|
* into) while performing the OAuth 3-legged login flow in a local browser (from the lost host where
|
||||||
|
* the SSH client resides).
|
||||||
|
*
|
||||||
|
* <p>When performing the login flow, an HTTP server will be listening on the remote port and have a
|
||||||
|
* redirect_uri of <code>http://localhost:remote_port</code>, which is only accessible from the
|
||||||
|
* remote host. By changing the redirect_uri to <code>http://localhost:forwarding_port</code>, it
|
||||||
|
* becomes accessible from the local host, if <code>local_host:forwarding_port</code> is forwarded
|
||||||
|
* to <code>remote_host:remote_port</code>.
|
||||||
|
*
|
||||||
|
* <p>Note that port forwarding is <b>required</b>. We cannot use the remote host's IP or reverse
|
||||||
|
* DNS address in the redirect URI, even if they are directly accessible from the local host,
|
||||||
|
* because the only allowed redirect URI scheme for desktops apps when sending a request to the
|
||||||
|
* Google OAuth server is the loopback address with a port.
|
||||||
|
*
|
||||||
|
* @see <href
|
||||||
|
* a=https://developers.google.com/identity/protocols/oauth2/native-app#request-parameter-redirect_uri>
|
||||||
|
* redirect_uri values </href>
|
||||||
|
*/
|
||||||
|
final class ForwardingServerReceiver implements VerificationCodeReceiver {
|
||||||
|
|
||||||
|
private final int forwarding_port;
|
||||||
|
private final LocalServerReceiver localServerReceiver = new LocalServerReceiver();
|
||||||
|
|
||||||
|
ForwardingServerReceiver(int forwarding_port) {
|
||||||
|
this.forwarding_port = forwarding_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRedirectUri() throws IOException {
|
||||||
|
String redirect_uri = localServerReceiver.getRedirectUri();
|
||||||
|
return redirect_uri.replace("localhost:" + getRemotePort(), "localhost:" + forwarding_port);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String waitForCode() throws IOException {
|
||||||
|
return localServerReceiver.waitForCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stop() throws IOException {
|
||||||
|
localServerReceiver.stop();
|
||||||
|
System.out.println("You can now exit from the SSH session created for port forwarding.");
|
||||||
|
}
|
||||||
|
|
||||||
|
int getRemotePort() {
|
||||||
|
return localServerReceiver.getPort();
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ import com.beust.jcommander.Parameters;
|
||||||
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
|
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
|
||||||
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
|
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
|
||||||
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
|
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
|
||||||
import com.google.api.client.googleapis.extensions.java6.auth.oauth2.GooglePromptReceiver;
|
import java.net.InetAddress;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
/** Authorizes the nomulus tool for OAuth 2.0 access to remote resources. */
|
/** Authorizes the nomulus tool for OAuth 2.0 access to remote resources. */
|
||||||
|
@ -30,24 +30,35 @@ final class LoginCommand implements Command {
|
||||||
@Inject @AuthModule.ClientScopeQualifier String clientScopeQualifier;
|
@Inject @AuthModule.ClientScopeQualifier String clientScopeQualifier;
|
||||||
|
|
||||||
@Parameter(
|
@Parameter(
|
||||||
names = "--remote",
|
names = "--port",
|
||||||
description =
|
description =
|
||||||
"Whether the command is run on a remote host where access to a browser is not available. "
|
"A free port on the local host. When set, it is assumed that the nomulus tool runs on a"
|
||||||
+ "If set to true, a URL will be given and a code is expected to be entered after "
|
+ " remote host whose browser is not accessible locally. i. e. if you SSH to a"
|
||||||
+ "the user completes authorization by visiting that URL.")
|
+ " machine and run `nomulus` there, the ssh client is on the local host and nomulus"
|
||||||
private boolean remote = false;
|
+ " runs on a remote host. You will need to forward the local port specified here to"
|
||||||
|
+ " a remote port that nomulus randomly picks. Follow the instruction when prompted.")
|
||||||
|
private int port = 0;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
AuthorizationCodeInstalledApp app;
|
AuthorizationCodeInstalledApp app;
|
||||||
if (remote) {
|
if (port != 0) {
|
||||||
|
String remote_host = InetAddress.getLocalHost().getHostName();
|
||||||
|
ForwardingServerReceiver forwardingServerReceiver = new ForwardingServerReceiver(port);
|
||||||
app =
|
app =
|
||||||
new AuthorizationCodeInstalledApp(
|
new AuthorizationCodeInstalledApp(
|
||||||
flow,
|
flow,
|
||||||
new GooglePromptReceiver(),
|
forwardingServerReceiver,
|
||||||
url -> {
|
url -> {
|
||||||
System.out.println("Please open the following address in your browser:");
|
int remote_port = forwardingServerReceiver.getRemotePort();
|
||||||
System.out.println(" " + url);
|
System.out.printf(
|
||||||
|
"Please first run the following command in a separate terminal on your local "
|
||||||
|
+ "host:\n\n ssh -L %s:localhost:%s %s\n\n",
|
||||||
|
port, remote_port, remote_host);
|
||||||
|
System.out.printf(
|
||||||
|
"Please then open the following URL in your local browser and follow the"
|
||||||
|
+ " instructions:\n\n %s\n\n",
|
||||||
|
url);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
app = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver());
|
app = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver());
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue