| /* |
| * 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.directory.server.kerberos.kdc; |
| |
| |
| import static org.junit.Assert.assertEquals; |
| |
| import java.io.File; |
| import java.io.IOException; |
| import java.util.Collections; |
| |
| import javax.security.auth.Subject; |
| import javax.security.auth.kerberos.KerberosTicket; |
| |
| import org.apache.commons.lang3.SystemUtils; |
| import org.apache.directory.api.ldap.model.entry.DefaultEntry; |
| import org.apache.directory.api.ldap.model.entry.DefaultModification; |
| import org.apache.directory.api.ldap.model.entry.Entry; |
| import org.apache.directory.api.ldap.model.entry.Modification; |
| import org.apache.directory.api.ldap.model.entry.ModificationOperation; |
| import org.apache.directory.api.ldap.model.exception.LdapException; |
| import org.apache.directory.api.util.FileUtils; |
| import org.apache.directory.api.util.Strings; |
| import org.apache.directory.server.core.api.LdapCoreSessionConnection; |
| import org.apache.directory.server.core.integ.AbstractLdapTestUnit; |
| import org.apache.directory.server.protocol.shared.transport.TcpTransport; |
| import org.apache.directory.server.protocol.shared.transport.Transport; |
| import org.apache.directory.shared.kerberos.codec.types.EncryptionType; |
| import org.apache.directory.shared.kerberos.crypto.checksum.ChecksumType; |
| import org.junit.After; |
| import org.junit.Before; |
| import org.junit.Rule; |
| import org.junit.rules.TemporaryFolder; |
| |
| |
| /** |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public class AbstractKerberosITest extends AbstractLdapTestUnit |
| { |
| public static final String USERS_DN = "ou=users,dc=example,dc=com"; |
| public static final String REALM = "EXAMPLE.COM"; |
| public static final String USER_UID = "hnelson"; |
| public static final String USER_PASSWORD = "secret"; |
| public static final String LDAP_SERVICE_NAME = "ldap"; |
| public static final String HOSTNAME = KerberosTestUtils.getHostName(); |
| |
| @Rule |
| public TemporaryFolder folder = new TemporaryFolder(); |
| |
| protected LdapCoreSessionConnection conn; |
| |
| |
| @Before |
| public void setUp() throws Exception |
| { |
| conn = new LdapCoreSessionConnection( service ); |
| |
| enableKerberosSchema(); |
| } |
| |
| |
| @After |
| public void tearDown() throws Exception |
| { |
| conn.close(); |
| } |
| |
| class ObtainTicketParameters |
| { |
| Class<? extends Transport> transport; |
| EncryptionType encryptionType; |
| ChecksumType checksumType; |
| Integer oldUdpPrefLimit; |
| Integer oldCksumtypeDefault; |
| |
| |
| public ObtainTicketParameters( Class<? extends Transport> transport, EncryptionType encryptionType, |
| ChecksumType checksumType ) |
| { |
| this.transport = transport; |
| this.encryptionType = encryptionType; |
| this.checksumType = checksumType; |
| } |
| } |
| |
| |
| /** |
| * Obtains a TGT and service tickets for the user. |
| * Also makes some assertions on the received tickets. |
| * |
| * @param encryptionType the encryption type to use |
| * @throws Exception |
| */ |
| protected void testObtainTickets( ObtainTicketParameters parameters ) throws Exception |
| { |
| setupEnv( parameters ); |
| Subject subject = new Subject(); |
| |
| KerberosTestUtils.obtainTGT( subject, USER_UID, USER_PASSWORD ); |
| |
| assertEquals( 1, subject.getPrivateCredentials().size() ); |
| assertEquals( 0, subject.getPublicCredentials().size() ); |
| |
| KerberosTestUtils.obtainServiceTickets( subject, USER_UID, LDAP_SERVICE_NAME, HOSTNAME ); |
| |
| assertEquals( 2, subject.getPrivateCredentials().size() ); |
| assertEquals( 0, subject.getPublicCredentials().size() ); |
| |
| for ( KerberosTicket kt : subject.getPrivateCredentials( KerberosTicket.class ) ) |
| { |
| // System.out.println( kt.getClient() ); |
| // System.out.println( kt.getServer() ); |
| // System.out.println( kt.getSessionKeyType() ); |
| assertEquals( parameters.encryptionType.getValue(), kt.getSessionKeyType() ); |
| } |
| } |
| |
| |
| private void enableKerberosSchema() throws LdapException |
| { |
| Modification mod = new DefaultModification( ModificationOperation.REPLACE_ATTRIBUTE, |
| "m-disabled", "FALSE" ); |
| conn.modify( "cn=Krb5kdc,ou=schema", mod ); |
| } |
| |
| |
| protected void setupEnv( ObtainTicketParameters parameters ) |
| throws Exception |
| { |
| // create krb5.conf with proper encryption type |
| String krb5confPath = createKrb5Conf( parameters.checksumType, parameters.encryptionType, parameters.transport == TcpTransport.class ); |
| System.setProperty( "java.security.krb5.conf", krb5confPath ); |
| |
| // change encryption type in KDC |
| kdcServer.getConfig().setEncryptionTypes( Collections.singleton( parameters.encryptionType ) ); |
| |
| // create principals |
| createPrincipal( "uid=" + USER_UID, "Last", "First Last", |
| USER_UID, USER_PASSWORD, USER_UID + "@" + REALM ); |
| |
| createPrincipal( "uid=krbtgt", "KDC Service", "KDC Service", |
| "krbtgt", "secret", "krbtgt/" + REALM + "@" + REALM ); |
| |
| String servicePrincipal = LDAP_SERVICE_NAME + "/" + HOSTNAME + "@" + REALM; |
| createPrincipal( "uid=ldap", "Service", "LDAP Service", |
| "ldap", "randall", servicePrincipal ); |
| } |
| |
| |
| /** |
| * Creates the krb5.conf file for the test. |
| * |
| * It looks similar to this: |
| * |
| * <pre> |
| * [libdefaults] |
| * default_realm = EXAMPLE.COM |
| * default_tkt_enctypes = aes256-cts-hmac-sha1-96 |
| * default_tgs_enctypes = aes256-cts-hmac-sha1-96 |
| * permitted_enctypes = aes256-cts-hmac-sha1-96 |
| * |
| * [realms] |
| * EXAMPLE.COM = { |
| * kdc = localhost:6088 |
| * } |
| * |
| * [domain_realm] |
| * .example.com = EXAMPLE.COM |
| * example.com = EXAMPLE.COM |
| * </pre> |
| * |
| * @param encryptionType |
| * @param checksumType |
| * @return the path to the krb5.conf file |
| * @throws IOException |
| */ |
| private String createKrb5Conf( ChecksumType checksumType, EncryptionType encryptionType, boolean isTcp ) throws IOException |
| { |
| File file = folder.newFile( "krb5.conf" ); |
| |
| String data = ""; |
| |
| data += "[libdefaults]" + SystemUtils.LINE_SEPARATOR; |
| data += "default_realm = " + REALM + SystemUtils.LINE_SEPARATOR; |
| data += "default_tkt_enctypes = " + encryptionType.getName() + SystemUtils.LINE_SEPARATOR; |
| data += "default_tgs_enctypes = " + encryptionType.getName() + SystemUtils.LINE_SEPARATOR; |
| data += "permitted_enctypes = " + encryptionType.getName() + SystemUtils.LINE_SEPARATOR; |
| // data += "default_checksum = " + checksumType.getName() + SystemUtils.LINE_SEPARATOR; |
| // data += "ap_req_checksum_type = " + checksumType.getName() + SystemUtils.LINE_SEPARATOR; |
| data += "default-checksum_type = " + checksumType.getName() + SystemUtils.LINE_SEPARATOR; |
| |
| if ( isTcp ) |
| { |
| data += "udp_preference_limit = 1" + SystemUtils.LINE_SEPARATOR; |
| } |
| |
| |
| data += "[realms]" + SystemUtils.LINE_SEPARATOR; |
| data += REALM + " = {" + SystemUtils.LINE_SEPARATOR; |
| data += "kdc = " + HOSTNAME + ":" + kdcServer.getTransports()[0].getPort() + SystemUtils.LINE_SEPARATOR; |
| data += "}" + SystemUtils.LINE_SEPARATOR; |
| |
| data += "[domain_realm]" + SystemUtils.LINE_SEPARATOR; |
| data += "." + Strings.toLowerCaseAscii( REALM ) + " = " + REALM + SystemUtils.LINE_SEPARATOR; |
| data += Strings.toLowerCaseAscii( REALM ) + " = " + REALM + SystemUtils.LINE_SEPARATOR; |
| |
| FileUtils.writeStringToFile( file, data ); |
| |
| return file.getAbsolutePath(); |
| } |
| |
| |
| private void createPrincipal( String rdn, String sn, String cn, |
| String uid, String userPassword, String principalName ) throws LdapException |
| { |
| Entry entry = new DefaultEntry(); |
| entry.setDn( rdn + "," + USERS_DN ); |
| entry.add( "objectClass", "top", "person", "inetOrgPerson", "krb5principal", "krb5kdcentry" ); |
| entry.add( "cn", cn ); |
| entry.add( "sn", sn ); |
| entry.add( "uid", uid ); |
| entry.add( "userPassword", userPassword ); |
| entry.add( "krb5PrincipalName", principalName ); |
| entry.add( "krb5KeyVersionNumber", "0" ); |
| conn.add( entry ); |
| } |
| |
| } |