Skip to content

Commit

Permalink
Merge pull request #1 from palantir/feature/kerberos
Browse files Browse the repository at this point in the history
Add Kerberos support again
  • Loading branch information
bluekeyes committed Aug 18, 2015
2 parents 59ca429 + 0b7cfc4 commit 7db30e8
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 14 deletions.
4 changes: 2 additions & 2 deletions ssh/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ dependencies {
compile project(':giraffe-core')

compile group: 'org.slf4j', name: 'slf4j-api', version: libVersions.slf4j
compile(group: 'com.hierynomus', name: 'sshj', version: '0.12.0') {
// force our version of slf4j-api in a way that persists in Ivy
compile(group: 'com.hierynomus', name: 'sshj', version: '0.13.0') {
// force our version of slf4j-api in a way that persists
exclude module: 'slf4j-api'
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* Copyright 2015 Palantir Technologies, Inc.
*
* 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.palantir.giraffe.ssh;

import java.io.IOException;

/**
* Authenticates SSH connections via GSS-API in a Kerberos environment.
*
* @author benh
*/
public class KerberosSshCredential extends SshCredential {

public static KerberosSshCredential of(String username) {
return new KerberosSshCredential(username);
}

public KerberosSshCredential(String username) {
super(username);
}

@Override
public void authenticate(SshAuthenticator authenticator) throws IOException {
authenticator.authByKerberos(this);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ private PasswordSshCredential(String username, char[] password) {

@Override
public void authenticate(SshAuthenticator authenticator) throws IOException {
authenticator.authByPassword(this, password.clone());
authenticator.authByPassword(this);
}

public char[] getPassword() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ private PublicKeySshCredential(String username, byte[] privateKey, Optional<Path

@Override
public void authenticate(SshAuthenticator authenticator) throws IOException {
authenticator.authByPublicKey(this, privateKey.clone());
authenticator.authByPublicKey(this);
}

public byte[] getPrivateKey() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@
*/
public interface SshAuthenticator extends Authenticator {

void authByPassword(SshCredential credential, char[] password) throws IOException;
void authByPassword(PasswordSshCredential credential) throws IOException;

void authByPublicKey(SshCredential credential, byte[] privateKey) throws IOException;
void authByPublicKey(PublicKeySshCredential credential) throws IOException;

void authByKerberos(KerberosSshCredential credential) throws IOException;

}
12 changes: 12 additions & 0 deletions ssh/src/main/java/com/palantir/giraffe/ssh/SshHostAccessor.java
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,18 @@ public static SshHostAccessor forKey(String hostname, String username, String pr
return forCredential(host, PublicKeySshCredential.of(username, privateKey));
}

/**
* Returns a new {@code SshHostAccessor} that authenticates as the given
* user using the system Kerberos configuration.
*
* @param hostname the name of the host to access
* @param username the user to authenticate as
*/
public static SshHostAccessor forKerberos(String hostname, String username) {
Host host = Host.fromHostname(hostname);
return forCredential(host, KerberosSshCredential.of(username));
}

/**
* Returns a new {@code SshHostAccessor} that authenticates using the given
* {@link SshCredential}.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,33 @@

import java.io.IOException;

import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
import javax.security.auth.login.Configuration;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

import org.ietf.jgss.GSSException;
import org.ietf.jgss.Oid;

import com.google.common.collect.ImmutableMap;
import com.palantir.giraffe.ssh.KerberosSshCredential;
import com.palantir.giraffe.ssh.PasswordSshCredential;
import com.palantir.giraffe.ssh.PublicKeySshCredential;
import com.palantir.giraffe.ssh.SshAuthenticator;
import com.palantir.giraffe.ssh.SshCredential;
import com.palantir.giraffe.ssh.SshSystemRequest;

import net.schmizz.sshj.Config;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import net.schmizz.sshj.userauth.UserAuthException;
import net.schmizz.sshj.userauth.keyprovider.KeyProvider;

final class SshConnectionFactory {

private static final String KRB_ENTRY_NAME = "GiraffeKrb5";

private final Config config;

public SshConnectionFactory(Config sshjConfiguration) {
Expand All @@ -50,24 +65,71 @@ public SSHClient newAuthedConnection(SshSystemRequest request) throws IOExceptio
return sshClient;
}

private final class Authenticator implements SshAuthenticator {
private static final class Authenticator implements SshAuthenticator {

private final SSHClient client;

public Authenticator(SSHClient client) {
this.client = client;
}

@Override
public void authByPassword(SshCredential credential, char[] password)
throws IOException {
client.authPassword(credential.getUsername(), password);
public void authByPassword(PasswordSshCredential credential) throws IOException {
client.authPassword(credential.getUsername(), credential.getPassword());
}

@Override
public void authByPublicKey(SshCredential credential, byte[] privateKey)
throws IOException {
KeyProvider keyProvider = client.loadKeys(new String(privateKey), null, null);
public void authByPublicKey(PublicKeySshCredential credential) throws IOException {
String privateKey = new String(credential.getPrivateKey());
KeyProvider keyProvider = client.loadKeys(privateKey, null, null);
client.authPublickey(credential.getUsername(), keyProvider);
}

@Override
public void authByKerberos(KerberosSshCredential credential) throws IOException {
String user = credential.getUsername();

LoginContext lc = null;
try {
lc = new LoginContext(KRB_ENTRY_NAME, null, null, new KrbAuthConfiguration(user));
lc.login();
} catch (LoginException e) {
throw new UserAuthException(e);
}

Oid krb5Oid;
try {
krb5Oid = new Oid("1.2.840.113554.1.2.2");
} catch (GSSException e) {
// this will never happen, krb5 OID is always valid
throw new AssertionError();
}
client.authGssApiWithMic(user, lc, krb5Oid);
}
}

private static final class KrbAuthConfiguration extends Configuration {
private final AppConfigurationEntry krbEntry;

KrbAuthConfiguration(String principal) {
krbEntry = new AppConfigurationEntry(
"com.sun.security.auth.module.Krb5LoginModule",
LoginModuleControlFlag.REQUIRED,
ImmutableMap.<String, String>builder()
.put("refreshKrb5Config", "true")
.put("useTicketCache", "true")
.put("doNotPrompt", "true")
.put("principal", principal)
.build());
}

@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
if (KRB_ENTRY_NAME.equals(name)) {
return new AppConfigurationEntry[] { krbEntry };
} else {
return null;
}
}
}
}

0 comments on commit 7db30e8

Please sign in to comment.