Authenticate /p/ HTTP and SSH access by password
Use HTTP digest authentication to verify user access to any of the /p/ URLs which do not permit anonymous requests. The SSH daemon now also honors the user's password. Change-Id: I6f8775077b3ee8fcb66a2d07c225f668afa0d530 Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
		| @@ -0,0 +1,102 @@ | ||||
| // Copyright (C) 2010 The Android Open Source Project | ||||
| // | ||||
| // 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 com.google.gerrit.sshd; | ||||
|  | ||||
| import static com.google.gerrit.sshd.SshUtil.AUTH_ATTEMPTED_AS; | ||||
| import static com.google.gerrit.sshd.SshUtil.AUTH_ERROR; | ||||
| import static com.google.gerrit.sshd.SshUtil.CURRENT_ACCOUNT; | ||||
|  | ||||
| import com.google.gerrit.reviewdb.AccountExternalId; | ||||
| import com.google.gerrit.server.account.AccountCache; | ||||
| import com.google.gerrit.server.account.AccountState; | ||||
| import com.google.gerrit.sshd.SshScopes.Context; | ||||
| import com.google.inject.Inject; | ||||
| import com.google.inject.Singleton; | ||||
|  | ||||
| import org.apache.mina.core.future.IoFuture; | ||||
| import org.apache.mina.core.future.IoFutureListener; | ||||
| import org.apache.sshd.server.PasswordAuthenticator; | ||||
| import org.apache.sshd.server.session.ServerSession; | ||||
|  | ||||
| /** | ||||
|  * Authenticates by password through {@link AccountExternalId} entities. | ||||
|  */ | ||||
| @Singleton | ||||
| class DatabasePasswordAuth implements PasswordAuthenticator { | ||||
|   private final AccountCache accountCache; | ||||
|   private final SshLog log; | ||||
|  | ||||
|   @Inject | ||||
|   DatabasePasswordAuth(final AccountCache ac, final SshLog l) { | ||||
|     accountCache = ac; | ||||
|     log = l; | ||||
|   } | ||||
|  | ||||
|   @Override | ||||
|   public boolean authenticate(final String username, final String password, | ||||
|       final ServerSession session) { | ||||
|     AccountState state = accountCache.getByUsername(username); | ||||
|     if (state == null) { | ||||
|       return fail(username, session, "user-not-found"); | ||||
|     } | ||||
|  | ||||
|     final String p = state.getPassword(username); | ||||
|     if (p == null) { | ||||
|       return fail(username, session, "no-password"); | ||||
|     } | ||||
|  | ||||
|     if (!p.equals(password)) { | ||||
|       return fail(username, session, "incorrect-password"); | ||||
|     } | ||||
|  | ||||
|     if (session.setAttribute(CURRENT_ACCOUNT, state.getAccount().getId()) == null) { | ||||
|       // If this is the first time we've authenticated this | ||||
|       // session, record a login event in the log and add | ||||
|       // a close listener to record a logout event. | ||||
|       // | ||||
|       final Context ctx = new Context(session); | ||||
|       final Context old = SshScopes.current.get(); | ||||
|       try { | ||||
|         SshScopes.current.set(ctx); | ||||
|         log.onLogin(); | ||||
|       } finally { | ||||
|         SshScopes.current.set(old); | ||||
|       } | ||||
|  | ||||
|       session.getIoSession().getCloseFuture().addListener( | ||||
|           new IoFutureListener<IoFuture>() { | ||||
|             @Override | ||||
|             public void operationComplete(IoFuture future) { | ||||
|               final Context old = SshScopes.current.get(); | ||||
|               try { | ||||
|                 SshScopes.current.set(ctx); | ||||
|                 log.onLogout(); | ||||
|               } finally { | ||||
|                 SshScopes.current.set(old); | ||||
|               } | ||||
|             } | ||||
|           }); | ||||
|     } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   private static boolean fail(final String username, | ||||
|       final ServerSession session, final String err) { | ||||
|     session.setAttribute(AUTH_ATTEMPTED_AS, username); | ||||
|     session.setAttribute(AUTH_ERROR, err); | ||||
|     return false; | ||||
|   } | ||||
| } | ||||
| @@ -32,10 +32,6 @@ import java.security.PublicKey; | ||||
|  | ||||
| /** | ||||
|  * Authenticates by public key through {@link AccountSshKey} entities. | ||||
|  * <p> | ||||
|  * The username supplied by the client must be the user's preferred email | ||||
|  * address, as listed in their Account entity. Only keys listed under that | ||||
|  * account as authorized keys are permitted to access the account. | ||||
|  */ | ||||
| @Singleton | ||||
| class DatabasePubKeyAuth implements PublickeyAuthenticator { | ||||
|   | ||||
| @@ -60,8 +60,10 @@ import org.apache.sshd.common.util.SecurityUtils; | ||||
| import org.apache.sshd.server.Command; | ||||
| import org.apache.sshd.server.CommandFactory; | ||||
| import org.apache.sshd.server.ForwardingFilter; | ||||
| import org.apache.sshd.server.PasswordAuthenticator; | ||||
| import org.apache.sshd.server.PublickeyAuthenticator; | ||||
| import org.apache.sshd.server.UserAuth; | ||||
| import org.apache.sshd.server.auth.UserAuthPassword; | ||||
| import org.apache.sshd.server.auth.UserAuthPublicKey; | ||||
| import org.apache.sshd.server.channel.ChannelDirectTcpip; | ||||
| import org.apache.sshd.server.channel.ChannelSession; | ||||
| @@ -119,6 +121,7 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener { | ||||
|  | ||||
|   @Inject | ||||
|   SshDaemon(final CommandFactory commandFactory, | ||||
|       final PasswordAuthenticator passAuth, | ||||
|       final PublickeyAuthenticator userAuth, | ||||
|       final KeyPairProvider hostKeyProvider, final IdGenerator idGenerator, | ||||
|       @GerritServerConfig final Config cfg, final SshLog sshLog) { | ||||
| @@ -140,7 +143,7 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener { | ||||
|     initForwardingFilter(); | ||||
|     initSubsystems(); | ||||
|     initCompression(); | ||||
|     initUserAuth(userAuth); | ||||
|     initUserAuth(passAuth, userAuth); | ||||
|     setKeyPairProvider(hostKeyProvider); | ||||
|     setCommandFactory(commandFactory); | ||||
|     setShellFactory(new NoShell()); | ||||
| @@ -452,9 +455,11 @@ public class SshDaemon extends SshServer implements SshInfo, LifecycleListener { | ||||
|   } | ||||
|  | ||||
|   @SuppressWarnings("unchecked") | ||||
|   private void initUserAuth(final PublickeyAuthenticator pubkey) { | ||||
|     setUserAuthFactories(Arrays | ||||
|         .<NamedFactory<UserAuth>> asList(new UserAuthPublicKey.Factory())); | ||||
|   private void initUserAuth(final PasswordAuthenticator pass, | ||||
|       final PublickeyAuthenticator pubkey) { | ||||
|     setUserAuthFactories(Arrays.<NamedFactory<UserAuth>> asList( | ||||
|         new UserAuthPublicKey.Factory(), new UserAuthPassword.Factory())); | ||||
|     setPasswordAuthenticator(pass); | ||||
|     setPublickeyAuthenticator(pubkey); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -47,6 +47,7 @@ import com.google.inject.servlet.SessionScoped; | ||||
| import org.apache.sshd.common.KeyPairProvider; | ||||
| import org.apache.sshd.common.session.AbstractSession; | ||||
| import org.apache.sshd.server.CommandFactory; | ||||
| import org.apache.sshd.server.PasswordAuthenticator; | ||||
| import org.apache.sshd.server.PublickeyAuthenticator; | ||||
| import org.apache.sshd.server.session.ServerSession; | ||||
| import org.kohsuke.args4j.spi.OptionHandler; | ||||
| @@ -81,6 +82,7 @@ public class SshModule extends FactoryModule { | ||||
|         .toProvider(CommandExecutorProvider.class).in(SINGLETON); | ||||
|  | ||||
|     bind(PublickeyAuthenticator.class).to(DatabasePubKeyAuth.class); | ||||
|     bind(PasswordAuthenticator.class).to(DatabasePasswordAuth.class); | ||||
|     bind(KeyPairProvider.class).toProvider(HostKeyProvider.class).in(SINGLETON); | ||||
|  | ||||
|     install(new DefaultCommandModule()); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Shawn O. Pearce
					Shawn O. Pearce