Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ADDED constrained delegation connection sample #188

Merged
merged 2 commits into from
Mar 17, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/samples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ The following samples are available:

7. sparse
* **SparseColumns** - how to detect column sets. It also shows a technique for parsing a column set's XML output, to get data from the sparse columns.

8. constrained
* **ConstrainedSample** - how to connect with Kerberos constrained delegation using an impersonated credential.


## Running Samples
Expand Down
68 changes: 68 additions & 0 deletions src/samples/constrained/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.microsoft.sqlserver.jdbc</groupId>
<artifactId>constrained</artifactId>
<version>0.0.1</version>

<packaging>jar</packaging>

<name>${project.artifactId}</name>
<url>https://github.com/Microsoft/mssql-jdbc/tree/master/src/samples</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>6.1.5.jre8-preview</version>
</dependency>
</dependencies>

<profiles>
<profile>
<id>ConstrainedSample</id>
<build>
<finalName>ConstrainedSample</finalName>

<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<configuration>
<mainClass>ConstrainedSample</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
</plugins>
</build>

</project>
161 changes: 161 additions & 0 deletions src/samples/constrained/src/main/java/ConstrainedSample.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import javax.security.auth.Subject;
import javax.security.auth.login.LoginException;
import javax.security.auth.spi.LoginModule;

import org.ietf.jgss.GSSCredential;
import org.ietf.jgss.GSSException;
import org.ietf.jgss.GSSManager;
import org.ietf.jgss.GSSName;
import org.ietf.jgss.Oid;

import com.sun.security.jgss.ExtendedGSSCredential;

/**
*
* Sample of constrained delegation connection.
*
* An intermediate service is necessary to impersonate the client. This service needs to be configured with the
* options:
* "Trust this user for delegation to specified services only"
* "Use any authentication protocol"
*
*/
public class ConstrainedSample {

// Connection properties
private static final String DRIVER_CLASS_NAME ="com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static final String CONNECTION_URI = "jdbc:sqlserver:// URI of the SQLServer";

private static final String TARGET_USER_NAME = "User to be impersonated";

// Impersonation service properties
private static final String SERVICE_PRINCIPAL = "SPN";
private static final String KEYTAB_ROUTE = "Route to the keytab file";

private static final Properties driverProperties;
private static Oid krb5Oid;

private static Subject serviceSubject;

static {

driverProperties = new Properties();
driverProperties.setProperty("integratedSecurity", "true");
driverProperties.setProperty("authenticationScheme", "JavaKerberos");

try {
krb5Oid = new Oid("1.2.840.113554.1.2.2");
} catch (GSSException e) {
System.out.println("Error creating Oid: " + e);
System.exit(-1);
}
}

public static void main(String... args) throws Exception {

Class.forName(DRIVER_CLASS_NAME).getConstructor().newInstance();
System.out.println("Service subject: " + doInitialLogin());

// Get impersonated user credentials thanks S4U2self mechanism
GSSCredential impersonatedUserCreds = impersonate();
System.out.println("Credentials for " + TARGET_USER_NAME + ": " + impersonatedUserCreds);

// Create a connection for target service thanks S4U2proxy mechanism
try (Connection con = createConnection(impersonatedUserCreds)) {
System.out.println("Connection succesfully: " + con);
}

}

/**
*
* Authenticate the intermediate server that is going to impersonate the client
*
* @return a subject for the intermediate server with the keytab credentials
* @throws PrivilegedActionException in case of failure
*/
private static Subject doInitialLogin() throws PrivilegedActionException {
serviceSubject = new Subject();

LoginModule krb5Module;
try {
krb5Module = (LoginModule) Class.forName("com.sun.security.auth.module.Krb5LoginModule").getConstructor()
.newInstance();
} catch (Exception e) {
System.out.print("Error loading Krb5LoginModule module: " + e);
throw new PrivilegedActionException(e);
}

System.setProperty("sun.security.krb5.debug", String.valueOf(true));

Map<String, String> options = new HashMap<>();
options.put("useKeyTab", "true");
options.put("storeKey", "true");
options.put("doNotPrompt", "true");
options.put("keyTab", KEYTAB_ROUTE);
options.put("principal", SERVICE_PRINCIPAL);
options.put("debug", "true");
options.put("isInitiator", "true");

Map<String, String> sharedState = new HashMap<>(0);

krb5Module.initialize(serviceSubject, null, sharedState, options);
try {
krb5Module.login();
krb5Module.commit();
} catch (LoginException e) {
System.out.print("Error authenticating with Kerberos: " + e);
try {
krb5Module.abort();
} catch (LoginException e1) {
System.out.print("Error aborting Kerberos authentication: " + e1);
throw new PrivilegedActionException(e);
}
throw new PrivilegedActionException(e);
}

return serviceSubject;
}

/**
* Generate the impersonated user credentials thanks to the S4U2self mechanism
*
* @return the client impersonated GSSCredential
* @throws PrivilegedActionException in case of failure
*/
private static GSSCredential impersonate() throws PrivilegedActionException {
return Subject.doAs(serviceSubject, (PrivilegedExceptionAction<GSSCredential>) () -> {
GSSManager manager = GSSManager.getInstance();

GSSCredential self = manager.createCredential(null, GSSCredential.DEFAULT_LIFETIME, krb5Oid,
GSSCredential.INITIATE_ONLY);
GSSName user = manager.createName(TARGET_USER_NAME, GSSName.NT_USER_NAME);
return ((ExtendedGSSCredential) self).impersonate(user);
});
}

/**
* Obtains a connection using an impersonated credential
*
* @param impersonatedUserCredential impersonated user credentials
* @return a connection to the SQL Server opened using the given impersonated credential
* @throws PrivilegedActionException in case of failure
*/
private static Connection createConnection(final GSSCredential impersonatedUserCredential)
throws PrivilegedActionException {

return Subject.doAs(new Subject(), (PrivilegedExceptionAction<Connection>) () -> {
driverProperties.put("gsscredential", impersonatedUserCredential);
return DriverManager.getConnection(CONNECTION_URI, driverProperties);
});
}

}