Skip to content

Commit

Permalink
Add Cache for KeyStore implementation (#13)
Browse files Browse the repository at this point in the history
* initial caching version

* change cache to verifyKey

* add refreshAfterWrite option

* fix typo

* remove throws from method declaration in (Caching)KeyStoreAccessTest and replace with assertDoesNotThrow
  • Loading branch information
eemhu authored May 27, 2024
1 parent ecd785d commit 28363db
Show file tree
Hide file tree
Showing 5 changed files with 302 additions and 17 deletions.
111 changes: 111 additions & 0 deletions src/main/java/com/teragrep/jai_02/keystore/CachingKeyStoreAccess.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Java Authentication Info jai_02
* Copyright (C) 2021 Suomen Kanuuna Oy
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://github.com/teragrep/teragrep/blob/main/LICENSE>.
*
*
* Additional permission under GNU Affero General Public License version 3
* section 7
*
* If you modify this Program, or any covered work, by linking or combining it
* with other code, such other code is not for that reason alone subject to any
* of the requirements of the GNU Affero GPL version 3 as long as this Program
* is the same Program as licensed from Suomen Kanuuna Oy without any additional
* modifications.
*
* Supplemented terms under GNU Affero General Public License version 3
* section 7
*
* Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified
* versions must be marked as "Modified version of" The Program.
*
* Names of the licensors and authors may not be used for publicity purposes.
*
* No rights are granted for use of trade names, trademarks, or service marks
* which are in The Program if any.
*
* Licensee must indemnify licensors and authors for any liability that these
* contractual assumptions impose on licensors and authors.
*
* To the extent this program is licensed as part of the Commercial versions of
* Teragrep, the applicable Commercial License may apply to this file if you as
* a licensee so wish it.
*/
package com.teragrep.jai_02.keystore;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.cert.CertificateException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
* Provides access to the KeyStore, such as loading, saving
* and deleting entries. Keeps track of the username->alias mapping
* via the UserToAliasMapping object.
*/
public class CachingKeyStoreAccess {
private final KeyStoreAccess keyStoreAccess;

// cache
private final LoadingCache<UserNameAndPassword, Boolean> loadingCache;

public CachingKeyStoreAccess(final KeyStoreAccess keyStoreAccess, final long secs) {
this.keyStoreAccess = keyStoreAccess;

CacheLoader<UserNameAndPassword, Boolean> cacheLoader = new CacheLoader<UserNameAndPassword, Boolean>() {

@Override
public Boolean load(UserNameAndPassword pe) throws Exception {
return keyStoreAccess.verifyKey(pe.username(), pe.password());
}
};

this.loadingCache = CacheBuilder.newBuilder().refreshAfterWrite(secs, TimeUnit.SECONDS).build(cacheLoader);

}

public PasswordEntry loadKey(final String username) throws UnrecoverableEntryException, KeyStoreException, InvalidKeyException {
return keyStoreAccess.loadKey(username);
}

public void saveKey(final String username, final char[] password) throws KeyStoreException {
keyStoreAccess.saveKey(username, password);
}

public boolean verifyKey(final String username, final char[] password) throws ExecutionException {
return loadingCache.get(new UserNameAndPassword(username, password));
}

public int deleteKey(final String usernameToRemove) throws KeyStoreException, IOException {
return keyStoreAccess.deleteKey(usernameToRemove);
}

public boolean checkForExistingAlias(final String usernameToCheck) throws KeyStoreException {
return keyStoreAccess.checkForExistingAlias(usernameToCheck);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ public int deleteKey(final String usernameToRemove) throws KeyStoreException, IO
return aliasesToRemove.size();
}

private boolean checkForExistingAlias(final String usernameToCheck) throws KeyStoreException {
public boolean checkForExistingAlias(final String usernameToCheck) throws KeyStoreException {
boolean exists = false;

final Enumeration<String> aliases = keyStore.aliases();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
/*
* Java Authentication Info jai_02
* Copyright (C) 2021 Suomen Kanuuna Oy
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://github.com/teragrep/teragrep/blob/main/LICENSE>.
*
*
* Additional permission under GNU Affero General Public License version 3
* section 7
*
* If you modify this Program, or any covered work, by linking or combining it
* with other code, such other code is not for that reason alone subject to any
* of the requirements of the GNU Affero GPL version 3 as long as this Program
* is the same Program as licensed from Suomen Kanuuna Oy without any additional
* modifications.
*
* Supplemented terms under GNU Affero General Public License version 3
* section 7
*
* Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified
* versions must be marked as "Modified version of" The Program.
*
* Names of the licensors and authors may not be used for publicity purposes.
*
* No rights are granted for use of trade names, trademarks, or service marks
* which are in The Program if any.
*
* Licensee must indemnify licensors and authors for any liability that these
* contractual assumptions impose on licensors and authors.
*
* To the extent this program is licensed as part of the Commercial versions of
* Teragrep, the applicable Commercial License may apply to this file if you as
* a licensee so wish it.
*/
package com.teragrep.jai_02.keystore;

public class UserNameAndPassword {
private final String username;
private final char[] password;

public UserNameAndPassword(String username, char[] password) {
this.username = username;
this.password = password;
}

public String username() {
return username;
}

public char[] password() {
return password;
}
}
107 changes: 107 additions & 0 deletions src/test/java/com/teragrep/jai_02/tests/CachingKeyStoreAccessTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* Java Authentication Info jai_02
* Copyright (C) 2021 Suomen Kanuuna Oy
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://github.com/teragrep/teragrep/blob/main/LICENSE>.
*
*
* Additional permission under GNU Affero General Public License version 3
* section 7
*
* If you modify this Program, or any covered work, by linking or combining it
* with other code, such other code is not for that reason alone subject to any
* of the requirements of the GNU Affero GPL version 3 as long as this Program
* is the same Program as licensed from Suomen Kanuuna Oy without any additional
* modifications.
*
* Supplemented terms under GNU Affero General Public License version 3
* section 7
*
* Origin of the software must be attributed to Suomen Kanuuna Oy. Any modified
* versions must be marked as "Modified version of" The Program.
*
* Names of the licensors and authors may not be used for publicity purposes.
*
* No rights are granted for use of trade names, trademarks, or service marks
* which are in The Program if any.
*
* Licensee must indemnify licensors and authors for any liability that these
* contractual assumptions impose on licensors and authors.
*
* To the extent this program is licensed as part of the Commercial versions of
* Teragrep, the applicable Commercial License may apply to this file if you as
* a licensee so wish it.
*/

package com.teragrep.jai_02.tests;

import com.teragrep.jai_02.keystore.CachingKeyStoreAccess;
import com.teragrep.jai_02.keystore.KeyStoreAccess;
import com.teragrep.jai_02.keystore.KeyStoreFactory;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.KeyStoreException;
import java.security.UnrecoverableEntryException;
import java.security.spec.InvalidKeySpecException;
import java.util.concurrent.ExecutionException;

public class CachingKeyStoreAccessTest {

private static String keyStorePath = "target/keystore.p12";
private static String keyStorePassword = "changeit";
private static String userName = "trusted-12";
private static String userPassWord = "XOsAqIhmKUTwWMjWwDaYmVgR8sl_l70H1oDPBw9z2yY";

private static CachingKeyStoreAccess cksa;
@BeforeAll
public static void prepare() {
Assertions.assertDoesNotThrow(() -> {
cksa = new CachingKeyStoreAccess(
new KeyStoreAccess(
new KeyStoreFactory(keyStorePath, keyStorePassword.toCharArray()).build(),
keyStorePath, keyStorePassword.toCharArray()), 10L);

cksa.deleteKey(userName);
});
}

public void save() {
Assertions.assertDoesNotThrow(() -> {
cksa.saveKey(
userName,
userPassWord.toCharArray());
});
}

public void verify() {
Assertions.assertDoesNotThrow(() -> {
boolean authOk = cksa.verifyKey(
userName,
userPassWord.toCharArray());

Assertions.assertTrue(authOk);
});
}

@Test
public void saveAndVerifyTest() {
save();
verify();
}
}

35 changes: 19 additions & 16 deletions src/test/java/com/teragrep/jai_02/tests/KeyStoreAccessTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -67,30 +67,33 @@ public class KeyStoreAccessTest {

private static KeyStoreAccess ksa;
@BeforeAll
public static void prepare() throws KeyStoreException, IOException {
ksa = new KeyStoreAccess(new KeyStoreFactory(keyStorePath, keyStorePassword.toCharArray()).build(), keyStorePath, keyStorePassword.toCharArray());
ksa.deleteKey(userName);
public static void prepare() {
Assertions.assertDoesNotThrow(() -> {
ksa = new KeyStoreAccess(new KeyStoreFactory(keyStorePath, keyStorePassword.toCharArray()).build(), keyStorePath, keyStorePassword.toCharArray());
ksa.deleteKey(userName);
});
}

public void save() throws KeyStoreException {
ksa.saveKey(
userName,
userPassWord.toCharArray());
public void save() {
Assertions.assertDoesNotThrow(() -> {
ksa.saveKey(
userName,
userPassWord.toCharArray());
});
}

public void verify() throws UnrecoverableEntryException, KeyStoreException,
InvalidKeySpecException, InvalidKeyException {
public void verify() {
Assertions.assertDoesNotThrow(() -> {
boolean authOk = ksa.verifyKey(
userName,
userPassWord.toCharArray());

boolean authOk = ksa.verifyKey(
userName,
userPassWord.toCharArray());

Assertions.assertTrue(authOk);
Assertions.assertTrue(authOk);
});
}

@Test
public void saveAndVerifyTest() throws KeyStoreException,
InvalidKeySpecException, UnrecoverableEntryException, InvalidKeyException {
public void saveAndVerifyTest() {
save();
verify();
}
Expand Down

0 comments on commit 28363db

Please sign in to comment.