blob: 12da0535d275a5266328bac89b6ad731431f178b [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.kerby.kerberos.kerb.integration.test;
import static org.junit.Assert.*;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.interfaces.RSAPrivateKey;
import java.util.Collections;
import org.apache.kerby.kerberos.kerb.KrbException;
import org.apache.kerby.kerberos.kerb.KrbRuntime;
import org.apache.kerby.kerberos.kerb.ccache.Credential;
import org.apache.kerby.kerberos.kerb.ccache.CredentialCache;
import org.apache.kerby.kerberos.kerb.client.KrbClient;
import org.apache.kerby.kerberos.kerb.client.KrbTokenClient;
import org.apache.kerby.kerberos.kerb.common.EncryptionUtil;
import org.apache.kerby.kerberos.kerb.common.PrivateKeyReader;
import org.apache.kerby.kerberos.kerb.crypto.EncryptionHandler;
import org.apache.kerby.kerberos.kerb.provider.TokenEncoder;
import org.apache.kerby.kerberos.kerb.type.ad.AdToken;
import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationData;
import org.apache.kerby.kerberos.kerb.type.ad.AuthorizationDataEntry;
import org.apache.kerby.kerberos.kerb.type.base.AuthToken;
import org.apache.kerby.kerberos.kerb.type.base.EncryptionKey;
import org.apache.kerby.kerberos.kerb.type.base.KeyUsage;
import org.apache.kerby.kerberos.kerb.type.base.KrbToken;
import org.apache.kerby.kerberos.kerb.type.base.TokenFormat;
import org.apache.kerby.kerberos.kerb.type.ticket.EncTicketPart;
import org.apache.kerby.kerberos.kerb.type.ticket.SgtTicket;
import org.apache.kerby.kerberos.kerb.type.ticket.TgtTicket;
import org.apache.kerby.kerberos.kerb.type.ticket.Ticket;
import org.apache.kerby.kerberos.provider.token.JwtTokenEncoder;
/**
* Some tests for JWT tokens using the Kerby client API
*/
public class JWTTokenTest extends TokenLoginTestBase {
@org.junit.Test
public void accessToken() throws Exception {
KrbClient client = getKrbClient();
// Get a TGT
TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
assertNotNull(tgt);
// Write to cache
Credential credential = new Credential(tgt);
CredentialCache cCache = new CredentialCache();
cCache.addCredential(credential);
cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
cCache.store(cCacheFile);
KrbTokenClient tokenClient = new KrbTokenClient(client);
tokenClient.setKdcHost(client.getSetting().getKdcHost());
tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
tokenClient.init();
// Create a JWT token
AuthToken authToken = issueToken(getClientPrincipal());
authToken.isAcToken(true);
authToken.isIdToken(false);
authToken.setAudiences(Collections.singletonList(getServerPrincipal()));
KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
PrivateKey signKey;
try (InputStream is = Files.newInputStream(getSignKeyFile().toPath())) {
signKey = PrivateKeyReader.loadPrivateKey(is);
}
krbToken.setTokenValue(signToken(authToken, signKey));
// Now get a SGT using the JWT
SgtTicket tkt = tokenClient.requestSgt(krbToken, getServerPrincipal(), cCacheFile.getPath());
assertTrue(tkt != null);
// Decrypt the ticket
Ticket ticket = tkt.getTicket();
EncryptionKey key = EncryptionHandler.string2Key(getServerPrincipal(), getServerPassword(),
ticket.getEncryptedEncPart().getEType());
EncTicketPart encPart =
EncryptionUtil.unseal(ticket.getEncryptedEncPart(),
key, KeyUsage.KDC_REP_TICKET, EncTicketPart.class);
// Examine the authorization data
AuthorizationData authzData = encPart.getAuthorizationData();
assertEquals(1, authzData.getElements().size());
AuthorizationDataEntry dataEntry = authzData.getElements().iterator().next();
AdToken token = dataEntry.getAuthzDataAs(AdToken.class);
KrbToken decodedKrbToken = token.getToken();
assertEquals(getClientPrincipal(), decodedKrbToken.getSubject());
assertEquals(getServerPrincipal(), decodedKrbToken.getAudiences().get(0));
cCacheFile.delete();
}
@org.junit.Test
public void accessTokenInvalidAudience() throws Exception {
KrbClient client = getKrbClient();
// Get a TGT
TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
assertNotNull(tgt);
// Write to cache
Credential credential = new Credential(tgt);
CredentialCache cCache = new CredentialCache();
cCache.addCredential(credential);
cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
cCache.store(cCacheFile);
KrbTokenClient tokenClient = new KrbTokenClient(client);
tokenClient.setKdcHost(client.getSetting().getKdcHost());
tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
tokenClient.init();
// Create a JWT token with an invalid audience
AuthToken authToken = issueToken(getClientPrincipal());
authToken.isAcToken(true);
authToken.isIdToken(false);
authToken.setAudiences(Collections.singletonList(getServerPrincipal() + "_"));
KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
PrivateKey signKey;
try (InputStream is = Files.newInputStream(getSignKeyFile().toPath())) {
signKey = PrivateKeyReader.loadPrivateKey(is);
}
krbToken.setTokenValue(signToken(authToken, signKey));
// Now get a SGT using the JWT
try {
tokenClient.requestSgt(krbToken, getServerPrincipal(), cCacheFile.getPath());
fail("Failure expected on an invalid audience");
} catch (KrbException ex) { //NOPMD
// expected
}
cCacheFile.delete();
}
@org.junit.Test
public void accessTokenInvalidSignature() throws Exception {
KrbClient client = getKrbClient();
// Get a TGT
TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
assertNotNull(tgt);
// Write to cache
Credential credential = new Credential(tgt);
CredentialCache cCache = new CredentialCache();
cCache.addCredential(credential);
cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
cCache.store(cCacheFile);
KrbTokenClient tokenClient = new KrbTokenClient(client);
tokenClient.setKdcHost(client.getSetting().getKdcHost());
tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
tokenClient.init();
// Create a JWT token with an invalid audience
AuthToken authToken = issueToken(getClientPrincipal());
authToken.isAcToken(true);
authToken.isIdToken(false);
authToken.setAudiences(Collections.singletonList(getServerPrincipal()));
KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
krbToken.setTokenValue(signToken(authToken, keyPair.getPrivate()));
// Now get a SGT using the JWT
try {
tokenClient.requestSgt(krbToken, getServerPrincipal(), cCacheFile.getPath());
fail("Failure expected on an invalid signature");
} catch (KrbException ex) { //NOPMD
// expected
}
cCacheFile.delete();
}
@org.junit.Test
public void accessTokenUnknownIssuer() throws Exception {
KrbClient client = getKrbClient();
// Get a TGT
TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
assertNotNull(tgt);
// Write to cache
Credential credential = new Credential(tgt);
CredentialCache cCache = new CredentialCache();
cCache.addCredential(credential);
cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
cCache.store(cCacheFile);
KrbTokenClient tokenClient = new KrbTokenClient(client);
tokenClient.setKdcHost(client.getSetting().getKdcHost());
tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
tokenClient.init();
// Create a JWT token with an invalid audience
AuthToken authToken = issueToken(getClientPrincipal());
authToken.isAcToken(true);
authToken.isIdToken(false);
authToken.setAudiences(Collections.singletonList(getServerPrincipal()));
authToken.setIssuer("unknown-issuer");
KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
PrivateKey signKey;
try (InputStream is = Files.newInputStream(getSignKeyFile().toPath())) {
signKey = PrivateKeyReader.loadPrivateKey(is);
}
krbToken.setTokenValue(signToken(authToken, signKey));
// Now get a SGT using the JWT
try {
tokenClient.requestSgt(krbToken, getServerPrincipal(), cCacheFile.getPath());
fail("Failure expected on an unknown issuer");
} catch (KrbException ex) { //NOPMD
// expected
}
cCacheFile.delete();
}
// Use the TGT here instead of an armor cache
@org.junit.Test
public void accessTokenUsingTicket() throws Exception {
KrbClient client = getKrbClient();
// Get a TGT
TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
assertNotNull(tgt);
KrbTokenClient tokenClient = new KrbTokenClient(client);
tokenClient.setKdcHost(client.getSetting().getKdcHost());
tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
tokenClient.init();
// Create a JWT token
AuthToken authToken = issueToken(getClientPrincipal());
authToken.isAcToken(true);
authToken.isIdToken(false);
authToken.setAudiences(Collections.singletonList(getServerPrincipal()));
KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
PrivateKey signKey;
try (InputStream is = Files.newInputStream(getSignKeyFile().toPath())) {
signKey = PrivateKeyReader.loadPrivateKey(is);
}
krbToken.setTokenValue(signToken(authToken, signKey));
// Now get a SGT using the JWT
SgtTicket tkt = tokenClient.requestSgt(krbToken, getServerPrincipal(), tgt);
assertTrue(tkt != null);
// Decrypt the ticket
Ticket ticket = tkt.getTicket();
EncryptionKey key = EncryptionHandler.string2Key(getServerPrincipal(), getServerPassword(),
ticket.getEncryptedEncPart().getEType());
EncTicketPart encPart =
EncryptionUtil.unseal(ticket.getEncryptedEncPart(),
key, KeyUsage.KDC_REP_TICKET, EncTicketPart.class);
// Examine the authorization data
AuthorizationData authzData = encPart.getAuthorizationData();
assertEquals(1, authzData.getElements().size());
AuthorizationDataEntry dataEntry = authzData.getElements().iterator().next();
AdToken token = dataEntry.getAuthzDataAs(AdToken.class);
KrbToken decodedKrbToken = token.getToken();
assertEquals(getClientPrincipal(), decodedKrbToken.getSubject());
assertEquals(getServerPrincipal(), decodedKrbToken.getAudiences().get(0));
}
@org.junit.Test
public void identityToken() throws Exception {
KrbClient client = getKrbClient();
// Get a TGT
TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
assertNotNull(tgt);
// Write to cache
Credential credential = new Credential(tgt);
CredentialCache cCache = new CredentialCache();
cCache.addCredential(credential);
cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
cCache.store(cCacheFile);
KrbTokenClient tokenClient = new KrbTokenClient(client);
tokenClient.setKdcHost(client.getSetting().getKdcHost());
tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
tokenClient.init();
// Create a JWT token
AuthToken authToken = issueToken(getClientPrincipal());
KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
PrivateKey signKey;
try (InputStream is = Files.newInputStream(getSignKeyFile().toPath())) {
signKey = PrivateKeyReader.loadPrivateKey(is);
}
krbToken.setTokenValue(signToken(authToken, signKey));
// Now get a TGT using the JWT token
tgt = tokenClient.requestTgt(krbToken, cCacheFile.getPath());
// Now get a SGT using the TGT
SgtTicket tkt = tokenClient.requestSgt(tgt, getServerPrincipal());
assertTrue(tkt != null);
// Decrypt the ticket
Ticket ticket = tkt.getTicket();
EncryptionKey key = EncryptionHandler.string2Key(getServerPrincipal(), getServerPassword(),
ticket.getEncryptedEncPart().getEType());
EncTicketPart encPart =
EncryptionUtil.unseal(ticket.getEncryptedEncPart(),
key, KeyUsage.KDC_REP_TICKET, EncTicketPart.class);
// Check the authorization data is not present
AuthorizationData authzData = encPart.getAuthorizationData();
assertNull(authzData);
cCacheFile.delete();
}
@org.junit.Test
public void identityTokenInvalidAudience() throws Exception {
KrbClient client = getKrbClient();
// Get a TGT
TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
assertNotNull(tgt);
// Write to cache
Credential credential = new Credential(tgt);
CredentialCache cCache = new CredentialCache();
cCache.addCredential(credential);
cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
cCache.store(cCacheFile);
KrbTokenClient tokenClient = new KrbTokenClient(client);
tokenClient.setKdcHost(client.getSetting().getKdcHost());
tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
tokenClient.init();
// Create a JWT token
AuthToken authToken = issueToken(getClientPrincipal());
authToken.setAudiences(Collections.singletonList(authToken.getAudiences().get(0) + "_"));
KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
PrivateKey signKey;
try (InputStream is = Files.newInputStream(getSignKeyFile().toPath())) {
signKey = PrivateKeyReader.loadPrivateKey(is);
}
krbToken.setTokenValue(signToken(authToken, signKey));
// Now get a TGT using the JWT token
try {
tokenClient.requestTgt(krbToken, cCacheFile.getPath());
fail("Failure expected on an invalid audience");
} catch (KrbException ex) { //NOPMD
// expected
}
cCacheFile.delete();
}
@org.junit.Test
public void identityTokenInvalidSignature() throws Exception {
KrbClient client = getKrbClient();
// Get a TGT
TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
assertNotNull(tgt);
// Write to cache
Credential credential = new Credential(tgt);
CredentialCache cCache = new CredentialCache();
cCache.addCredential(credential);
cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
cCache.store(cCacheFile);
KrbTokenClient tokenClient = new KrbTokenClient(client);
tokenClient.setKdcHost(client.getSetting().getKdcHost());
tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
tokenClient.init();
// Create a JWT token
AuthToken authToken = issueToken(getClientPrincipal());
authToken.setAudiences(Collections.singletonList(authToken.getAudiences().get(0) + "_"));
KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
KeyPair keyPair = KeyPairGenerator.getInstance("RSA").generateKeyPair();
krbToken.setTokenValue(signToken(authToken, keyPair.getPrivate()));
// Now get a TGT using the JWT token
try {
tokenClient.requestTgt(krbToken, cCacheFile.getPath());
fail("Failure expected on an invalid signature");
} catch (KrbException ex) { //NOPMD
// expected
}
cCacheFile.delete();
}
@org.junit.Test
public void identityTokenUnknownIssuer() throws Exception {
KrbClient client = getKrbClient();
// Get a TGT
TgtTicket tgt = client.requestTgt(getClientPrincipal(), getClientPassword());
assertNotNull(tgt);
// Write to cache
Credential credential = new Credential(tgt);
CredentialCache cCache = new CredentialCache();
cCache.addCredential(credential);
cCache.setPrimaryPrincipal(tgt.getClientPrincipal());
File cCacheFile = File.createTempFile("krb5_" + getClientPrincipal(), "cc");
cCache.store(cCacheFile);
KrbTokenClient tokenClient = new KrbTokenClient(client);
tokenClient.setKdcHost(client.getSetting().getKdcHost());
tokenClient.setKdcTcpPort(client.getSetting().getKdcTcpPort());
tokenClient.setKdcRealm(client.getSetting().getKdcRealm());
tokenClient.init();
// Create a JWT token
AuthToken authToken = issueToken(getClientPrincipal());
authToken.setIssuer("unknown-issuer");
KrbToken krbToken = new KrbToken(authToken, TokenFormat.JWT);
PrivateKey signKey;
try (InputStream is = Files.newInputStream(getSignKeyFile().toPath())) {
signKey = PrivateKeyReader.loadPrivateKey(is);
}
krbToken.setTokenValue(signToken(authToken, signKey));
// Now get a TGT using the JWT token
try {
tokenClient.requestTgt(krbToken, cCacheFile.getPath());
fail("Failure expected on an unknown issuer");
} catch (KrbException ex) { //NOPMD
// expected
}
cCacheFile.delete();
}
private byte[] signToken(AuthToken authToken, PrivateKey signKey) throws Exception {
TokenEncoder tokenEncoder = KrbRuntime.getTokenProvider("JWT").createTokenEncoder();
assertTrue(tokenEncoder instanceof JwtTokenEncoder);
((JwtTokenEncoder) tokenEncoder).setSignKey((RSAPrivateKey) signKey);
return tokenEncoder.encodeAsBytes(authToken);
}
}