From e97c01c140841667b1fa50a9ffa41bb60952e4ec Mon Sep 17 00:00:00 2001
From: Fabrice Bacchella <fbacchella@spamcop.net>
Date: Tue, 26 May 2015 17:42:07 -0400
Subject: [PATCH] Invalid kerberos patches, works now and with a test.

---
 src/test/java/com/gitblit/tests/SshKerberosAuthenticationTest.java |   76 +++++++++++++++++++++++++
 src/main/java/com/gitblit/manager/IAuthenticationManager.java      |   10 +++
 src/test/java/com/gitblit/tests/GitBlitSuite.java                  |    2 
 src/main/java/com/gitblit/transport/ssh/SshDaemon.java             |    2 
 src/main/java/com/gitblit/manager/GitblitManager.java              |    5 +
 src/main/java/com/gitblit/manager/AuthenticationManager.java       |   29 +++++++++
 src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java   |   52 +++++++++++++++++
 build.moxie                                                        |    1 
 8 files changed, 175 insertions(+), 2 deletions(-)

diff --git a/build.moxie b/build.moxie
index 237c3d3..6863968 100644
--- a/build.moxie
+++ b/build.moxie
@@ -185,6 +185,7 @@
 - test 'org.seleniumhq.selenium:selenium-java:${selenium.version}' @jar
 - test 'org.seleniumhq.selenium:selenium-support:${selenium.version}' @jar
 - test 'org.seleniumhq.selenium:selenium-firefox-driver:${selenium.version}'
+- test 'org.mockito:mockito-core:1.10.19'
 # Dependencies with the "build" scope are retrieved
 # and injected into the Ant runtime classpath
 - build 'jacoco'
diff --git a/src/main/java/com/gitblit/manager/AuthenticationManager.java b/src/main/java/com/gitblit/manager/AuthenticationManager.java
index cbf0a1b..38e45a6 100644
--- a/src/main/java/com/gitblit/manager/AuthenticationManager.java
+++ b/src/main/java/com/gitblit/manager/AuthenticationManager.java
@@ -374,6 +374,35 @@
 
 
 	/**
+	 * Return the UserModel for already authenticated user.
+	 *
+	 * This implementation assumes that the authentication has already take place
+	 * (e.g. SSHDaemon) and that this is a validation/verification of the user.
+	 *
+	 * @param username
+	 * @return a user object or null
+	 */
+	@Override
+	public UserModel authenticate(String username) {
+		if (username != null) {
+			if (!StringUtils.isEmpty(username)) {
+				UserModel user = userManager.getUserModel(username);
+				if (user != null) {
+					// existing user
+					logger.debug(MessageFormat.format("{0} authenticated externally", user.username));
+					return validateAuthentication(user, AuthenticationType.CONTAINER);
+				}
+				logger.warn(MessageFormat.format("Failed to find UserModel for {0} during external authentication",
+							username));
+			}
+		} else {
+			logger.warn("Empty user passed to AuthenticationManager.authenticate!");
+		}
+		return null;
+	}
+
+
+	/**
 	 * This method allows the authentication manager to reject authentication
 	 * attempts.  It is called after the username/secret have been verified to
 	 * ensure that the authentication technique has been logged.
diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java
index deaa534..8d25b3f 100644
--- a/src/main/java/com/gitblit/manager/GitblitManager.java
+++ b/src/main/java/com/gitblit/manager/GitblitManager.java
@@ -662,6 +662,11 @@
 	}
 
 	@Override
+	public UserModel authenticate(String username) {
+		return authenticationManager.authenticate(username);
+	}
+
+	@Override
 	public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) {
 		UserModel user = authenticationManager.authenticate(httpRequest, requiresCertificate);
 		if (user == null) {
diff --git a/src/main/java/com/gitblit/manager/IAuthenticationManager.java b/src/main/java/com/gitblit/manager/IAuthenticationManager.java
index d48ec53..c81092b 100644
--- a/src/main/java/com/gitblit/manager/IAuthenticationManager.java
+++ b/src/main/java/com/gitblit/manager/IAuthenticationManager.java
@@ -71,6 +71,16 @@
 	UserModel authenticate(String username, char[] password);
 
 	/**
+	 * Return the UserModel for already authenticated user.
+	 *
+	 * @see IUserService.authenticate(String, char[])
+	 * @param username
+	 * @return a user object or null
+	 * @since 1.7.0
+	 */
+	UserModel authenticate(String username);
+
+	/**
 	 * Returns the Gitlbit cookie in the request.
 	 *
 	 * @param request
diff --git a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
index ec7d7c3..0ff5c28 100644
--- a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
+++ b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
@@ -134,7 +134,7 @@
 		//Will do GSS ?
 		GSSAuthenticator gssAuthenticator = null;
 		if(settings.getBoolean(Keys.git.sshWithKrb5, false)) {
-			gssAuthenticator = new GSSAuthenticator();
+			gssAuthenticator = new SshKrbAuthenticator(gitblit);
 			String keytabString = settings.getString(Keys.git.sshKrb5Keytab,
 					"");
 			if(! keytabString.isEmpty()) {
diff --git a/src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java b/src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java
new file mode 100644
index 0000000..8170c93
--- /dev/null
+++ b/src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 gitblit.com.
+ *
+ * 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.gitblit.transport.ssh;
+
+import com.gitblit.manager.IAuthenticationManager;
+import com.gitblit.models.UserModel;
+import java.util.Locale;
+import org.apache.sshd.server.auth.gss.GSSAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SshKrbAuthenticator extends GSSAuthenticator {
+	
+	protected final Logger log = LoggerFactory.getLogger(getClass());
+	protected final IAuthenticationManager authManager;
+
+	public SshKrbAuthenticator(IAuthenticationManager authManager) {
+		this.authManager = authManager;
+		log.info("registry  {}", authManager);
+	}
+
+	public boolean validateIdentity(ServerSession session, String identity) {
+		log.info("identify with kerberos {}", identity);
+		SshDaemonClient client = (SshDaemonClient)session.getAttribute(SshDaemonClient.KEY);
+		if (client.getUser() != null) {
+			log.info("{} has already authenticated!", identity);
+			return true;
+		}
+		String username = identity.toLowerCase(Locale.US);
+		UserModel user = authManager.authenticate(username);
+		if (user != null) {
+			client.setUser(user);
+			return true;
+		}
+		log.warn("could not authenticate {} for SSH", username);
+		return false;
+	}
+}
diff --git a/src/test/java/com/gitblit/tests/GitBlitSuite.java b/src/test/java/com/gitblit/tests/GitBlitSuite.java
index bf6834d..79a0920 100644
--- a/src/test/java/com/gitblit/tests/GitBlitSuite.java
+++ b/src/test/java/com/gitblit/tests/GitBlitSuite.java
@@ -65,7 +65,7 @@
 		FanoutServiceTest.class, Issue0259Test.class, Issue0271Test.class, HtpasswdAuthenticationTest.class,
 		ModelUtilsTest.class, JnaUtilsTest.class, LdapSyncServiceTest.class, FileTicketServiceTest.class,
 		BranchTicketServiceTest.class, RedisTicketServiceTest.class, AuthenticationManagerTest.class,
-		SshKeysDispatcherTest.class, UITicketTest.class, PathUtilsTest.class })
+		SshKeysDispatcherTest.class, UITicketTest.class, PathUtilsTest.class, SshKerberosAuthenticationTest.class })
 public class GitBlitSuite {
 
 	public static final File BASEFOLDER = new File("data");
diff --git a/src/test/java/com/gitblit/tests/SshKerberosAuthenticationTest.java b/src/test/java/com/gitblit/tests/SshKerberosAuthenticationTest.java
new file mode 100644
index 0000000..1bebf61
--- /dev/null
+++ b/src/test/java/com/gitblit/tests/SshKerberosAuthenticationTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015 gitblit.com.
+ *
+ * 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.gitblit.tests;
+
+import org.apache.sshd.server.auth.gss.GSSAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import com.gitblit.manager.AuthenticationManager;
+import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.manager.IUserManager;
+import com.gitblit.models.UserModel;
+import com.gitblit.transport.ssh.SshDaemonClient;
+import com.gitblit.transport.ssh.SshKrbAuthenticator;
+
+public class SshKerberosAuthenticationTest extends GitblitUnitTest {
+
+	private static class UserModelWrapper {
+		public UserModel um;
+	}
+
+	@Test
+	public void testUserManager() {
+		IRuntimeManager rm = Mockito.mock(IRuntimeManager.class);
+		
+		//Build an UserManager that can build a UserModel
+		IUserManager im = Mockito.mock(IUserManager.class);
+		Mockito.doAnswer(new Answer<Object>() {
+			public Object answer(InvocationOnMock invocation) {
+				Object[] args = invocation.getArguments();
+				String user = (String) args[0];
+				return new UserModel(user);
+			}           
+		}).when(im).getUserModel(Mockito.anyString());
+
+		AuthenticationManager am = new AuthenticationManager(rm, im);
+				
+		GSSAuthenticator gssAuthenticator = new SshKrbAuthenticator(am);
+
+		ServerSession session = Mockito.mock(ServerSession.class);
+
+		//Build an SshDaemonClient that can set and get the UserModel
+		final UserModelWrapper umw = new UserModelWrapper();
+		SshDaemonClient client = Mockito.mock(SshDaemonClient.class);
+		Mockito.when(client.getUser()).thenReturn(umw.um);
+		Mockito.doAnswer(new Answer<Object>() {
+			public Object answer(InvocationOnMock invocation) {
+				Object[] args = invocation.getArguments();
+				UserModel um = (UserModel) args[0];
+				umw.um = um;
+				return null;
+			}           
+		}).when(client).setUser(Mockito.any(UserModel.class));
+
+		Mockito.when(session.getAttribute(SshDaemonClient.KEY)).thenReturn(client);
+		Assert.assertTrue(gssAuthenticator.validateIdentity(session, "jhappy"));
+
+	}
+}

--
Gitblit v1.9.1