From 430f6ad3fed6f0f62b6df023357bd84583744cfd Mon Sep 17 00:00:00 2001 From: Colm O hEigeartaigh Date: Fri, 7 Aug 2026 10:31:51 +0100 Subject: [PATCH] Set the correct permissions on the created keytabs --- .../identitybackend/JsonIdentityBackend.java | 5 ++ ...sonIdentityBackendFilePermissionsTest.java | 63 ++++++++++++++++ kerby-kerb/kerb-admin/pom.xml | 10 +++ .../kerb/admin/kadmin/local/AdminHelper.java | 7 ++ .../local/AdminHelperFilePermissionsTest.java | 72 +++++++++++++++++++ .../kerberos/kerb/client/KrbClientBase.java | 6 +- ...KrbClientBaseCacheFilePermissionsTest.java | 59 +++++++++++++++ 7 files changed, 220 insertions(+), 2 deletions(-) create mode 100644 kerby-backend/json-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/JsonIdentityBackendFilePermissionsTest.java create mode 100644 kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelperFilePermissionsTest.java create mode 100644 kerby-kerb/kerb-client/src/test/java/org/apache/kerby/kerberos/kerb/client/KrbClientBaseCacheFilePermissionsTest.java diff --git a/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java b/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java index 797d60d62..2ad3ec233 100644 --- a/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java +++ b/kerby-backend/json-backend/src/main/java/org/apache/kerby/kerberos/kdc/identitybackend/JsonIdentityBackend.java @@ -125,6 +125,11 @@ protected void doInitialize() throws KrbException { if (!jsonKdbFile.exists()) { try { jsonKdbFile.createNewFile(); + // Restrict to owner-only (0600) to protect principal key material + jsonKdbFile.setReadable(false, false); + jsonKdbFile.setWritable(false, false); + jsonKdbFile.setReadable(true, true); + jsonKdbFile.setWritable(true, true); } catch (IOException e) { throw new KrbException("Failed to create " + jsonKdbFile.getAbsolutePath()); } diff --git a/kerby-backend/json-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/JsonIdentityBackendFilePermissionsTest.java b/kerby-backend/json-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/JsonIdentityBackendFilePermissionsTest.java new file mode 100644 index 000000000..590332f38 --- /dev/null +++ b/kerby-backend/json-backend/src/test/java/org/apache/kerby/kerberos/kerb/identity/backend/JsonIdentityBackendFilePermissionsTest.java @@ -0,0 +1,63 @@ +/** + * 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.identity.backend; + +import org.apache.kerby.config.Conf; +import org.apache.kerby.config.Config; +import org.apache.kerby.kerberos.kdc.identitybackend.JsonIdentityBackend; +import org.apache.kerby.kerberos.kerb.KrbException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.util.Set; + +import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; +import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +public class JsonIdentityBackendFilePermissionsTest { + + @TempDir + Path tempDir; + + @Test + public void testKdbFileHasOwnerOnlyPermissions() throws KrbException, Exception { + assumeTrue(tempDir.getFileSystem().supportedFileAttributeViews().contains("posix"), + "Skipping: POSIX file permissions not supported on this OS"); + + Config backendConfig = new Conf(); + backendConfig.setString(JsonIdentityBackend.JSON_IDENTITY_BACKEND_DIR, + tempDir.toString()); + JsonIdentityBackend backend = new JsonIdentityBackend(backendConfig); + backend.initialize(); + + Path kdbFile = tempDir.resolve("json-backend.json"); + assertThat(kdbFile).exists(); + + Set perms = Files.getPosixFilePermissions(kdbFile); + assertThat(perms) + .as("KDB file should be readable and writable by owner only") + .containsExactlyInAnyOrder(OWNER_READ, OWNER_WRITE); + } +} diff --git a/kerby-kerb/kerb-admin/pom.xml b/kerby-kerb/kerb-admin/pom.xml index c53a51f63..b3f6769c6 100644 --- a/kerby-kerb/kerb-admin/pom.xml +++ b/kerby-kerb/kerb-admin/pom.xml @@ -49,5 +49,15 @@ xnio-api ${xnio-api.version} + + org.junit.jupiter + junit-jupiter-engine + test + + + org.assertj + assertj-core + test + diff --git a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelper.java b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelper.java index b3fc01f8e..a2704a434 100644 --- a/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelper.java +++ b/kerby-kerb/kerb-admin/src/main/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelper.java @@ -136,6 +136,13 @@ public static Keytab createOrLoadKeytab(File keytabFile) throws KrbException { throw new KrbException("Failed to create keytab file " + keytabFile.getAbsolutePath()); } + // Restrict to owner-only (0600) to protect key material + keytabFile.setReadable(false, false); + keytabFile.setWritable(false, false); + keytabFile.setReadable(true, true); + keytabFile.setWritable(true, true); + keytab = new Keytab(); + } else if (keytabFile.length() == 0) { keytab = new Keytab(); } else { keytab = Keytab.loadKeytab(keytabFile); diff --git a/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelperFilePermissionsTest.java b/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelperFilePermissionsTest.java new file mode 100644 index 000000000..0a6efb7bf --- /dev/null +++ b/kerby-kerb/kerb-admin/src/test/java/org/apache/kerby/kerberos/kerb/admin/kadmin/local/AdminHelperFilePermissionsTest.java @@ -0,0 +1,72 @@ +/** + * 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.admin.kadmin.local; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.util.Set; + +import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; +import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +public class AdminHelperFilePermissionsTest { + + @TempDir + Path tempDir; + + @Test + public void testNewKeytabFileHasOwnerOnlyPermissions() throws Exception { + assumeTrue(tempDir.getFileSystem().supportedFileAttributeViews().contains("posix"), + "Skipping: POSIX file permissions not supported on this OS"); + + File keytabFile = tempDir.resolve("test.keytab").toFile(); + AdminHelper.createOrLoadKeytab(keytabFile); + + Set perms = Files.getPosixFilePermissions(keytabFile.toPath()); + assertThat(perms) + .as("keytab file should be readable and writable by owner only") + .containsExactlyInAnyOrder(OWNER_READ, OWNER_WRITE); + } + + @Test + public void testExistingKeytabLoadDoesNotBroadenPermissions() throws Exception { + assumeTrue(tempDir.getFileSystem().supportedFileAttributeViews().contains("posix"), + "Skipping: POSIX file permissions not supported on this OS"); + + File keytabFile = tempDir.resolve("existing.keytab").toFile(); + // Create the file with restricted permissions first, then reload it + AdminHelper.createOrLoadKeytab(keytabFile); + AdminHelper.createOrLoadKeytab(keytabFile); + + Set perms = Files.getPosixFilePermissions(keytabFile.toPath()); + assertThat(perms) + .as("loading an existing keytab should not introduce group/other read permissions") + .doesNotContain( + PosixFilePermission.GROUP_READ, PosixFilePermission.GROUP_WRITE, + PosixFilePermission.OTHERS_READ, PosixFilePermission.OTHERS_WRITE); + } +} diff --git a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbClientBase.java b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbClientBase.java index 08fd14f4d..762617cf3 100644 --- a/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbClientBase.java +++ b/kerby-kerb/kerb-client/src/main/java/org/apache/kerby/kerberos/kerb/client/KrbClientBase.java @@ -334,10 +334,12 @@ private void createCacheFile(File ccacheFile) throws KrbException { throw new KrbException("Failed to create ccache file " + ccacheFile.getAbsolutePath()); } - // sets read-write permissions to owner only + // Restrict to owner-only (0600) to protect credential cache contents + ccacheFile.setReadable(false, false); + ccacheFile.setWritable(false, false); ccacheFile.setReadable(true, true); if (!ccacheFile.setWritable(true, true)) { - throw new KrbException("Cache file is not readable."); + throw new KrbException("Cache file is not writable."); } } catch (IOException e) { throw new KrbException("Failed to create ccache file " diff --git a/kerby-kerb/kerb-client/src/test/java/org/apache/kerby/kerberos/kerb/client/KrbClientBaseCacheFilePermissionsTest.java b/kerby-kerb/kerb-client/src/test/java/org/apache/kerby/kerberos/kerb/client/KrbClientBaseCacheFilePermissionsTest.java new file mode 100644 index 000000000..d3b451fe9 --- /dev/null +++ b/kerby-kerb/kerb-client/src/test/java/org/apache/kerby/kerberos/kerb/client/KrbClientBaseCacheFilePermissionsTest.java @@ -0,0 +1,59 @@ +/** + * 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.client; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + +import java.io.File; +import java.lang.reflect.Method; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.attribute.PosixFilePermission; +import java.util.Set; + +import static java.nio.file.attribute.PosixFilePermission.OWNER_READ; +import static java.nio.file.attribute.PosixFilePermission.OWNER_WRITE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assumptions.assumeTrue; + +public class KrbClientBaseCacheFilePermissionsTest { + + @TempDir + Path tempDir; + + @Test + public void testCreatedCacheFileHasOwnerOnlyPermissions() throws Exception { + assumeTrue(tempDir.getFileSystem().supportedFileAttributeViews().contains("posix"), + "Skipping: POSIX file permissions not supported on this OS"); + + File ccacheFile = tempDir.resolve("test.ccache").toFile(); + KrbClientBase client = new KrbClientBase(new KrbConfig()); + + Method createCacheFile = KrbClientBase.class.getDeclaredMethod("createCacheFile", File.class); + createCacheFile.setAccessible(true); + createCacheFile.invoke(client, ccacheFile); + + Set perms = Files.getPosixFilePermissions(ccacheFile.toPath()); + assertThat(perms) + .as("credential cache file should be readable and writable by owner only") + .containsExactlyInAnyOrder(OWNER_READ, OWNER_WRITE); + } +}