-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Adam Gilat
committed
Jul 31, 2018
1 parent
996763b
commit 2ebfcf9
Showing
3 changed files
with
111 additions
and
187 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
187 changes: 56 additions & 131 deletions
187
src/test/java/io.okro.kafka/SpiffePrincipalBuilderTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,162 +1,87 @@ | ||
package io.okro.kafka; | ||
|
||
import java.util.concurrent.TimeUnit; | ||
import org.apache.kafka.common.security.auth.KafkaPrincipal; | ||
import org.apache.kafka.common.security.auth.PlaintextAuthenticationContext; | ||
import org.apache.kafka.common.security.auth.SslAuthenticationContext; | ||
import org.junit.Test; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import javax.net.ssl.SSLPeerUnverifiedException; | ||
import javax.net.ssl.SSLSession; | ||
import java.io.InputStream; | ||
import java.net.InetAddress; | ||
import java.net.UnknownHostException; | ||
import java.security.cert.Certificate; | ||
import java.security.cert.CertificateException; | ||
import java.security.cert.CertificateFactory; | ||
import java.security.cert.X509Certificate; | ||
import java.net.InetAddress; | ||
import javax.net.ssl.SSLSession; | ||
|
||
import org.apache.kafka.common.security.auth.*; | ||
|
||
import org.apache.commons.io.IOUtils; | ||
|
||
import org.easymock.EasyMock; | ||
import org.easymock.EasyMockSupport; | ||
import org.junit.Test; | ||
import static org.junit.Assert.assertEquals; | ||
import static org.junit.Assert.assertNotNull; | ||
|
||
public class SpiffePrincipalBuilderTest extends EasyMockSupport { | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.when; | ||
|
||
private X509Certificate getResourceAsCert(String resourcePath) | ||
throws java.io.IOException, java.security.cert.CertificateException { | ||
public class SpiffePrincipalBuilderTest { | ||
|
||
private SslAuthenticationContext mockedSslContext(String certPath) throws CertificateException, SSLPeerUnverifiedException, UnknownHostException { | ||
// load cert | ||
ClassLoader classLoader = getClass().getClassLoader(); | ||
try { | ||
// Read cert | ||
ByteArrayInputStream certInputStream = | ||
new ByteArrayInputStream(IOUtils.toByteArray(classLoader.getResourceAsStream(resourcePath))); | ||
|
||
// Parse as X509 certificate | ||
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); | ||
return (X509Certificate) certificateFactory.generateCertificate(certInputStream); | ||
|
||
} catch (java.io.IOException | java.security.cert.CertificateException e) { | ||
System.out.println("Problem with reading the certificate file. " + e.toString()); | ||
throw e; | ||
} | ||
InputStream in = classLoader.getResourceAsStream(certPath); | ||
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); | ||
X509Certificate cert = (X509Certificate) certificateFactory.generateCertificate(in); | ||
|
||
// mock ssl session | ||
SSLSession session = mock(SSLSession.class); | ||
when(session.getPeerCertificates()).thenReturn(new Certificate[]{cert}); | ||
return new SslAuthenticationContext(session, InetAddress.getLocalHost()); | ||
} | ||
|
||
/** | ||
* X509 V3 with a SPIFFE-based SAN extension. | ||
* Should result in 'SPIFFE:[spiffe://uri]' | ||
*/ | ||
@Test | ||
public void TestSubjectOnlyCert() { | ||
// Tests an X509 V1 certificate with no SAN extension | ||
public void TestSpiffeCert() throws CertificateException, SSLPeerUnverifiedException, UnknownHostException { | ||
SslAuthenticationContext context = mockedSslContext("spiffe-cert.pem"); | ||
KafkaPrincipal principal = new SpiffePrincipalBuilder().build(context); | ||
|
||
try { | ||
X509Certificate cert = getResourceAsCert("subject-only-cert.pem"); | ||
|
||
// Mock SSLSession getPeerCertificates(), we bypass alllll the handshake parts because... out of scope. | ||
SSLSession session = mock(SSLSession.class); | ||
EasyMock.expect(session.getPeerCertificates()).andReturn(new Certificate[] {cert}); | ||
|
||
replayAll(); | ||
|
||
// Build KafkaPrincipal | ||
SpiffePrincipalBuilder builder = new SpiffePrincipalBuilder(); | ||
|
||
KafkaPrincipal principal = builder.build( | ||
new SslAuthenticationContext(session, InetAddress.getLocalHost())); | ||
|
||
// Identity type should be "User" | ||
assertEquals(KafkaPrincipal.USER_TYPE, principal.getPrincipalType()); | ||
|
||
// Identity should be a string | ||
assertNotNull(principal.getName()); | ||
|
||
System.out.println("Principal: " + principal.toString()); | ||
|
||
} catch (java.io.IOException | java.security.cert.CertificateException e) { | ||
System.out.println("Problem with reading the certificate file. " + e.toString()); | ||
} | ||
assertEquals("SPIFFE", principal.getPrincipalType()); | ||
assertEquals(principal.getName(), "spiffe://srv1.okro.io"); | ||
} | ||
|
||
/** | ||
* X509 V1 certificate with no SAN extension. | ||
* Should fall back to 'User:CN=[CN]' | ||
*/ | ||
@Test | ||
public void TestSpiffeCert() { | ||
// Tests an X509 V3 with SAN extension holding a SPIFFE ID | ||
|
||
try { | ||
X509Certificate cert = getResourceAsCert("spiffe-cert.pem"); | ||
|
||
// Mock SSLSession getPeerCertificates(), we bypass alllll the handshake parts because... out of scope. | ||
SSLSession session = mock(SSLSession.class); | ||
EasyMock.expect(session.getPeerCertificates()).andReturn(new Certificate[] {cert}); | ||
public void TestSubjectOnlyCert() throws CertificateException, SSLPeerUnverifiedException, UnknownHostException { | ||
SslAuthenticationContext context = mockedSslContext("subject-only-cert.pem"); | ||
KafkaPrincipal principal = new SpiffePrincipalBuilder().build(context); | ||
|
||
replayAll(); | ||
|
||
// Build KafkaPrincipal | ||
SpiffePrincipalBuilder builder = new SpiffePrincipalBuilder(); | ||
|
||
KafkaPrincipal principal = builder.build( | ||
new SslAuthenticationContext(session, InetAddress.getLocalHost())); | ||
|
||
// Identity type should be "SPIFFE" | ||
assertEquals("SPIFFE", principal.getPrincipalType()); | ||
|
||
// Identity should be a string | ||
assertNotNull(principal.getName()); | ||
|
||
System.out.println("Principal: " + principal.toString()); | ||
|
||
} catch (java.io.IOException | java.security.cert.CertificateException e) { | ||
System.out.println("Problem with reading the certificate file. " + e.toString()); | ||
} | ||
assertEquals(KafkaPrincipal.USER_TYPE, principal.getPrincipalType()); | ||
assertEquals(principal.getName(), "CN=srv2,OU=architects,O=okro.io,L=Tel-Aviv,ST=Tel-Aviv,C=IL"); | ||
} | ||
|
||
/** | ||
* X509 V3 with a non-SPIFFE SAN extension. | ||
* Should fall back to 'User:CN=[CN]' | ||
*/ | ||
@Test | ||
public void TestSanNoSpiffeCert() { | ||
// Tests an X509 V3 with SAN extension holding a regular FQDN | ||
|
||
try { | ||
X509Certificate cert = getResourceAsCert("san-no-spiffe-cert.pem"); | ||
|
||
// Mock SSLSession getPeerCertificates(), we bypass alllll the handshake parts because... out of scope. | ||
SSLSession session = mock(SSLSession.class); | ||
EasyMock.expect(session.getPeerCertificates()).andReturn(new Certificate[] {cert}); | ||
|
||
replayAll(); | ||
|
||
// Build KafkaPrincipal | ||
SpiffePrincipalBuilder builder = new SpiffePrincipalBuilder(); | ||
|
||
KafkaPrincipal principal = builder.build( | ||
new SslAuthenticationContext(session, InetAddress.getLocalHost())); | ||
public void TestSanNoSpiffeCert() throws CertificateException, SSLPeerUnverifiedException, UnknownHostException { | ||
SslAuthenticationContext context = mockedSslContext("san-no-spiffe-cert.pem"); | ||
KafkaPrincipal principal = new SpiffePrincipalBuilder().build(context); | ||
|
||
// Identity type should be "User" | ||
assertEquals(KafkaPrincipal.USER_TYPE, principal.getPrincipalType()); | ||
|
||
// Identity should be a string | ||
assertNotNull(principal.getName()); | ||
|
||
System.out.println("Principal: " + principal.toString()); | ||
|
||
} catch (java.io.IOException | java.security.cert.CertificateException e) { | ||
System.out.println("Problem with reading the certificate file. " + e.toString()); | ||
} | ||
assertEquals(KafkaPrincipal.USER_TYPE, principal.getPrincipalType()); | ||
assertEquals(principal.getName(), "CN=srv3,OU=architects,O=okro.io,L=Tel-Aviv,ST=Tel-Aviv,C=IL"); | ||
} | ||
|
||
/** | ||
* Non-SSL context. | ||
* Should be unauthenticated. | ||
*/ | ||
@Test | ||
public void TestNoSSLContext() throws java.net.UnknownHostException { | ||
// Tests non-SSL context behavior | ||
|
||
SpiffePrincipalBuilder builder = new SpiffePrincipalBuilder(); | ||
|
||
KafkaPrincipal principal = builder.build( | ||
new PlaintextAuthenticationContext(InetAddress.getLocalHost())); | ||
PlaintextAuthenticationContext context = new PlaintextAuthenticationContext(InetAddress.getLocalHost()); | ||
KafkaPrincipal principal = new SpiffePrincipalBuilder().build(context); | ||
|
||
// Identity type should be KafkaPrincipal.ANONYMOUS | ||
assertEquals(KafkaPrincipal.ANONYMOUS, principal); | ||
|
||
System.out.println("Principal: " + principal.toString()); | ||
} | ||
|
||
@Test | ||
public void TestAwareness() throws InterruptedException { | ||
// Tests a reviewer's awareness | ||
TimeUnit.SECONDS.sleep(1); | ||
|
||
// Identity type should be KafkaPrincipal.ANONYMOUS | ||
assertEquals(42, 42); | ||
} | ||
} |