-
Notifications
You must be signed in to change notification settings - Fork 682
/
KerberosClientsKerbyTests.java
183 lines (154 loc) · 7.39 KB
/
KerberosClientsKerbyTests.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package org.pac4j.kerberos.client.direct;
import org.apache.kerby.kerberos.kdc.impl.NettyKdcServerImpl;
import org.apache.kerby.kerberos.kerb.KrbException;
import org.apache.kerby.kerberos.kerb.server.SimpleKdcServer;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.pac4j.core.client.Client;
import org.pac4j.core.context.HttpConstants;
import org.pac4j.core.context.MockWebContext;
import org.pac4j.core.exception.HttpAction;
import org.pac4j.core.util.TestsConstants;
import org.pac4j.kerberos.client.indirect.IndirectKerberosClient;
import org.pac4j.kerberos.credentials.KerberosCredentials;
import org.pac4j.kerberos.credentials.authenticator.KerberosAuthenticator;
import org.pac4j.kerberos.credentials.authenticator.SunJaasKerberosTicketValidator;
import org.pac4j.kerberos.profile.KerberosProfile;
import org.springframework.core.io.FileSystemResource;
import java.io.File;
import java.io.IOException;
import static junit.framework.TestCase.assertNull;
import static org.junit.Assert.*;
/**
* This tests both Direct and Indirect Kerberos clients.
* Both clients behave the same except then when credentials are invalid or not specified.
* - .getCredentials() in direct client
* * returns NULL
* - .getCredentials() in indirect client raises an exception:
* * raises a HttpAction "401 Authenticate: Negotiate"
*
* This is a test with real kerberos ticket validation:
* - spins up a mini/lightweight Kerberos server (using Apache Kerby)
* - generates the keytabs for service and client
* - generates a real service ticket, and passes it to mock context
* - checks that the ticket is correctly validated, and yields a correct client ID
*
* @author Vidmantas Zemleris, at Kensu.io
* @since 2.1.0
*/
public class KerberosClientsKerbyTests implements TestsConstants {
private static SimpleKdcServer kerbyServer;
static String clientPrincipal = "clientPrincipal@MYREALM.LT";
static String clientPassword = "clientPrincipal";
static String servicePrincipal = "HTTP/lala.mydomain.de@MYREALM.LT"; // i.e. HTTP/full-qualified-domain-name@DOMAIN
static String serviceName = "HTTP@lala.mydomain.de";
static String serviceKeyTabFileName = "/tmp/testServiceKeyTabFile";
static File serviceKeytabFile = new File(serviceKeyTabFileName);
@BeforeClass
public static void beforeAll() throws KrbException, IOException {
setupKerbyServer();
}
@AfterClass
public static void afterAll() throws KrbException {
kerbyServer.stop();
}
private static void setupKerbyServer() throws KrbException, IOException {
kerbyServer = new SimpleKdcServer();
kerbyServer.setKdcHost("localhost");
kerbyServer.setKdcRealm("MYREALM.LT");
kerbyServer.setAllowUdp(true);
//kerbyServer.setWorkDir(new File(basedir + "/target"));
kerbyServer.setInnerKdcImpl(new NettyKdcServerImpl(kerbyServer.getKdcSetting()));
kerbyServer.init();
// Create principals
kerbyServer.createPrincipal(clientPrincipal, clientPassword);
kerbyServer.createPrincipal(servicePrincipal, "servicePrincipal");
kerbyServer.getKadmin().exportKeytab(serviceKeytabFile, servicePrincipal);
//System.out.println(new String(Files.readAllBytes(serviceKeytabFile.toPath())));
kerbyServer.start();
}
@Test
public void testDirectNoAuth() {
// a request without "Authentication: (Negotiate|Kerberos) SomeToken" header, yields NULL credentials
assertNull(setupDirectKerberosClient().getCredentials(MockWebContext.create()));
}
@Test
public void testDirectAuthenticationWithRealTicket() throws Exception {
checkWithGoodTicket(setupDirectKerberosClient());
}
// =====================
// Indirect client below
// =====================
@Test
public void testDirectIncorrectAuth() {
// a request with an incorrect Kerberos token, yields NULL credentials also
final MockWebContext context = MockWebContext.create()
.addRequestHeader(HttpConstants.AUTHORIZATION_HEADER, "Negotiate " + "AAAbbAA123");
assertNull(setupDirectKerberosClient().getCredentials(context));
}
@Test
public void testIndirectNoAuth() {
// a request without "Authentication: (Negotiate|Kerberos) SomeToken" header
assertGetCredentialsFailsWithAuthRequired(setupIndirectKerberosClient(), MockWebContext.create(),"Performing a 401 HTTP action");
}
@Test
public void testIndirectIncorrectAuth() {
// a request with an incorrect Kerberos token, yields NULL credentials also
final MockWebContext context = MockWebContext.create()
.addRequestHeader(HttpConstants.AUTHORIZATION_HEADER, "Negotiate " + "AAAbbAA123");
assertGetCredentialsFailsWithAuthRequired(setupIndirectKerberosClient(), context, "Performing a 401 HTTP action");
}
@Test
public void testIndirectAuthenticationWithRealTicket() throws Exception {
checkWithGoodTicket(setupIndirectKerberosClient());
}
// ===============================
// Test helpers
// ===============================
private void assertGetCredentialsFailsWithAuthRequired(
IndirectKerberosClient kerbClient,
MockWebContext context,
String expectedMsg) {
try {
kerbClient.getCredentials(context);
fail("should throw HttpAction");
} catch (final HttpAction e) {
assertEquals(401, context.getResponseStatus());
assertEquals("Negotiate", context.getResponseHeaders().get(HttpConstants.AUTHENTICATE_HEADER));
assertEquals(expectedMsg, e.getMessage());
}
}
private void checkWithGoodTicket(Client<KerberosCredentials, KerberosProfile> client) throws Exception {
String spnegoWebTicket = SpnegoServiceTicketHelper.getGSSTicket(clientPrincipal, clientPassword, serviceName);
// mock web request
final MockWebContext context = mockWebRequestContext(spnegoWebTicket);
final KerberosCredentials credentials = client.getCredentials(context);
assertNotNull(credentials);
System.out.println(credentials);
final KerberosProfile profile = client.getUserProfile(credentials, context);
assertNotNull(profile);
assertEquals(clientPrincipal, profile.getId());
}
private DirectKerberosClient setupDirectKerberosClient() {
return new DirectKerberosClient(new KerberosAuthenticator(getKerberosValidator()));
}
private IndirectKerberosClient setupIndirectKerberosClient() {
IndirectKerberosClient client = new IndirectKerberosClient(new KerberosAuthenticator(getKerberosValidator()));
client.setCallbackUrl("http://dummy.com/");
return client;
}
private SunJaasKerberosTicketValidator getKerberosValidator() {
SunJaasKerberosTicketValidator validator = new SunJaasKerberosTicketValidator();
validator.setServicePrincipal(servicePrincipal);
validator.setKeyTabLocation(new FileSystemResource(serviceKeytabFile));
validator.setDebug(true);
return validator;
}
private MockWebContext mockWebRequestContext(String spnegoWebTicket) {
System.out.println("spnegoWebTicket:" + spnegoWebTicket);
final MockWebContext context = MockWebContext.create();
context.addRequestHeader(HttpConstants.AUTHORIZATION_HEADER, "Negotiate " + spnegoWebTicket);
return context;
}
}